Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate lazy-load application design

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)

like image 640
Johan Sjöberg Avatar asked Feb 17 '11 09:02

Johan Sjöberg


People also ask

How does lazy loading work in Hibernate?

Hibernate now can "lazy-load" the children, which means that it does not actually load all the children when loading the parent. Instead, it loads them when requested to do so. You can either request this explicitly or, and this is far more common, hibernate will load them automatically when you try to access a child.

Is lazy loading a design pattern?

Lazy loading (also known as asynchronous loading) is a design pattern commonly used in computer programming and mostly in web design and development to defer initialization of an object until the point at which it is needed. It can contribute to efficiency in the program's operation if properly and appropriately used.

Is lazy loading default in Hibernate?

1. Working with lazy associations. By default, Hibernate uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.

What is difference between lazy loading and eager loading in Hibernate?

Eager Loading is a design pattern in which data initialization occurs on the spot. Lazy Loading is a design pattern which is used to defer initialization of an object as long as it's possible.


2 Answers

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.

like image 53
axtavt Avatar answered Oct 01 '22 16:10

axtavt


I am not sure which problem (caused by lazyness) you're hinting to, but for me the biggest pain is to avoid losing session context in my own application caches. Typical case:

  • object foo is loaded and put into a map;
  • another thread takes this object from the map and calls foo.getBar() (something that was never called before and is lazy evaluated);
  • boom!

So, to address this we have a number of rules:

  • wrap sessions as transparently as possible (e.g. OpenSessionInViewFilter for webapps);
  • have common API for threads/thread pools where db session bind/unbind is done somewhere high in the hierarchy (wrapped in try/finally) so subclasses don't have to think about it;
  • when passing objects between threads, pass IDs instead of objects themselves. Receiving thread can load object if it needs to;
  • when caching objects, never cache objects but their ids. Have an abstract method in your DAO or manager class to load the object from 2nd level Hibernate cache when you know the ID. The cost of retrieving objects from 2nd level Hibernate cache is still far cheaper than going to DB.

This, as you can see, is indeed nowhere close to non-invasive and transparent. But the cost is still bearable, to compare with the price I'd have to pay for eager loading. The problem with latter is that sometimes it leads to the butterfly effect when loading single referenced object, let alone a collection of entities. Memory consumption, CPU usage and latency to mention the least are also far worse, so I guess I can live with it.

like image 41
mindas Avatar answered Oct 01 '22 15:10

mindas