Support for entity relationships is a great time-saving feature in Hibernate, but it can also be a trap for the unsuspecting developer. Handling relationships between entities can be a complex business, and I for one am glad for all the support that Hibernate provides. Hibernate's assistance, however, can do more harm than good when it comes to performance considerations. Because Hibernate does such a good job of hiding what SQL is generated for entity relationships and when it is executed, it is all too easy to produce poorly performing code and not realize it. Hibernate does provide a number of features to optimize performance, especially for relationships, such as the first and second level cache, lazy loading, and eager fetching. This multitude of features, however, can compound the problem when developers are unaware of them or of how they work.
This article focuses on lazy versus non-lazy relationships. In Hibernate 3 relationships are by default lazy: when an entity is loaded, the related entity or collection will not be loaded until it is accessed. In Hibernate 2, the default was non-lazy relationships. This default was changed in Hibernate 3 because of all the problems people encountered with non-lazy relationships. Despite the change in default in Hibernate 3, I have still seen developers explicitly use non-lazy relationships in the mistaken belief that they will provide a performance boost. I believe their assumption is that because Hibernate loads the non-lazy related entities at the same time as it loads the base entity, Hibernate must do this in a single SQL statement which is therefore more efficient. This is not true.
Hibernate's actual behavior is easy to see once you turn on SQL logging. Hibernate will issue one query to load the entities, and then issue one or more additional SQL queries in order to load the related entities. This does not seem so bad for a single relationship, but consider a typical application with a network of related entities. If all the relationships are non-lazy, then loading one entity will load all the related entities in the network. If collection relationships are involved the problem can become even worse. In certain scenarios, such as when loading a collection of child records that each have a non-lazy relationship to another entity, Hibernate will perform 1+N queries: one query to load the collection of children, and one query per child entity (N queries total) to load the related record for each child.
To provide a concrete example, consider the following object model.

The corresponding classes are summarized as follows:
class Customer {
public Collection getOrders();
}
class Order {
public Customer getCustomer();
public PaymentMethod getPaymentMethod();
}
class PaymentMethod {
public Order getOrder();
}
Let us assume that the relationship between Order and PaymentMethod is non-lazy. What happens when we have a single Customer and access its orders? Calling the getOrders() method on Customer when Customer is persistent and the orders collection has not yet been initialized causes Hibernate to issue a query to load the orders:
select * from Order where Customer_FK = ?
Each row returned by this query is converted by Hibernate into an Order instance which is then associated with the existing Customer object. Because the relationship to PaymentMethod is non-lazy, however, Hibernate must also load the corresponding PaymentMethod object via an additional query. I.e.
select * from PaymentMethod where Order_FK = ?
This PaymentMethod query is executed for each Order, so if there are N orders on the customer, Hibernate will execute N+1 queries. This is despite the relationship between Order and PaymentMethod being one-to-one. If it was an one-to-many relationship instead with M PaymentMethod instances for each Order, the performance would be even worse: 1+N*M queries total. On a recent project where multiple relationships were configured as non-lazy (compared to just one relationship in this example), I have seen a single operation result in hundreds of queries being executed to load in almost the entire related object graph.
The solution to this problem is easy: use only lazy relationships. I have a hard time thinking of any scenario where a non-lazy relationship would be a good idea. They certainly do not help performance, since the same set of SQL queries is issued for lazy and non-lazy relationships - it is just that lazy relationships result in queries being deferred until they are needed. If you do want to improve the performance of loading related entities then eager fetching is the feature to use.
This article is one of a series on Hibernate Tips & Tricks.
If you find this article helpful, please make a donation.
When you are sending objects to a remote client application, you can’t use lazy relationships if you actually need the data in the client. Don’t you think that’s a pretty common case where you can’t use a lazy relationship?
Good question. You can still use a lazy relationship – you just need to instantiate it on the server before sending the objects to the client. Forgetting to do this instantiation can be a source of errors, but I still think the other benefits of lazy relationships beat out this one isolated negative.
The other option is to still use a lazy relationship with OSIV pattern so that the hibernate session is closed on the client side. This will help us not to instantiate the objects on the server but client can decide it on what objects it wants to use.