Hibernate lazy-load application design

Johan Sjöberg picture Johan Sjöberg · Feb 17, 2011 · Viewed 21.6k times · Source

I tend to use Hibernate in combination with Spring framework and it's declarative transaction demarcation capabilities (e.g., @Transactional).

As we all known, hibernate tries to be as non-invasive and as transparent as possible, however this proves a bit more challenging when employing lazy-loaded relationships.


I see a number of design alternatives with different levels of transparency.

  1. Make relationships not lazy-loaded (e.g., fetchType=FetchType.EAGER)
    • This vioalites the entire idea of lazy loading ..
  2. Initialize collections using Hibernate.initialize(proxyObj);
    • This implies relatively high-coupling to the DAO
    • Although we can define an interface with initialize, other implementations are not guaranteed to provide any equivalent.
  3. Add transaction behaviour to the persistent Model objects themselves (using either dynamic proxy or @Transactional)
    • I've not tried the dynamic proxy approach, although I never seemed to get @Transactional working on the persistent objects themselves. Probably due to that hibernate is operation on a proxy to bein with.
    • Loss of control when transactions are actually taking place
  4. Provide both lazy/non-lazy API, e.g, loadData() and loadDataWithDeps()
    • Forces the application to know when to employ which routine, again tight coupling
    • Method overflow, loadDataWithA(), ...., loadDataWithX()
  5. Force lookup for dependencies, e.g., by only providing byId() operations
    • Requires alot of non-object oriented routines, e.g., findZzzById(zid), and then getYyyIds(zid) instead of z.getY()
    • It can be useful to fetch each object in a collection one-by-one if there's a large processing overhead between the transactions.
  6. Make part of the application @Transactional instead of only the DAO
    • Possible considerations of nested transactions
    • Requires routines adapted for transaction management (e.g., suffiently small)
    • Small programmatic impact, although might result in large transactions
  7. Provide the DAO with dynamic fetch profiles, e.g., loadData(id, fetchProfile);
    • Applications must know which profile to use when
  8. AoP type of transactions, e.g., intercept operations and perform transactions when necessary
    • Requires byte-code manipulation or proxy usage
    • Loss of control when transactions are performed
    • Black magic, as always :)

Did I miss any option?


Which is your preferred approach when trying to minimize the impact of lazy-loaded relationships in your application design?

(Oh, and sorry for WoT)

Answer

axtavt picture axtavt · Feb 17, 2011

As we all known, hibernate tries to be as non-invasive and as transparent as possible

I would say the initial assumption is wrong. Transaparent persistence is a myth, since application always should take care of entity lifecycle and of size of object graph being loaded.

Note that Hibernate can't read thoughts, therefore if you know that you need a particular set of dependencies for a particular operation, you need to express your intentions to Hibernate somehow.

From this point of view, solutions that express these intentions explicitly (namely, 2, 4 and 7) look reasonable and don't suffer from the lack of transparency.