Quantcast
Channel: Java Team at Kentor » Frameworks
Viewing all articles
Browse latest Browse all 26

Hibernate and JPA guidelines [part 1]

$
0
0

I recently had a cooperation with some colleagues from the Oracle team, putting together a document with some guidelines and tips for working with Hibernate/JPA and Oracle from a performance point of view. I decided to take some of these general guidelines and tips for Hibernate/JPA to do a three part serie with blogposts here on our blog. Each topic is divided into three parts; problem, suggestion and value. Each topic evolves from a identified problem and then makes a suggestion for dealing with the problem and a value for what benefits you get from using the suggestion. Anyone working with Hibernate or JPA should take some of these guidelines and tips under consideration. They are not just for improving performance. Some are more general best practices to ensure quality, easier coding and performance.

1. Always specify FetchType and preferably LAZY

Problem: In Hibernate/JPA you can choose which kind of FetchType you will use for relations between entities.
Often developers ignores specifying FetchType either because they don’t know what to specify or relying on the default FetchType. When configuring Hibernate with XML-configuration the default FetchType is always LAZY. But when using annotations for configuration the default FetchType varies depending on the realtion. For OneToOne and ManyToOne relations the default FetchType is EAGER and for the rest it is LAZY. This makes it confusing for other developers to know which FetchType that is actually used when it’s not specified. I worst case the wrong FetchType is used when the developers presumed another FetchType was the default one. Significant performance problems can be introduced by using the wrong kind of FetchType.

Suggestion: Always specify a FetchType for relations between entities. You should also consider to always specifying the FetchType to LAZY to avoid unnecessary data to be fetched by Hibernate when it’s not needed in the code. Note that when using FetchType LAZY you should also use Join fetch, described in the next guideline, when you need the relation to be populated.

Value: To always specify the FetchType makes the code more readable so that you don’t have to think about which FetchType that is being used as it is specified in the code. You eliminate the risk of the wrong FetchType being used due to misunderstanding of which FetchType that is the default one. Also by having the general rule to always specifying LAZY as the FetchType you make it easier for developers to know which FetchType to specify. That way you also reduces the risk of unnecessary fetching by Hibernate.

2. Use join fetch for initializing lazy relations

Problem: When having lazy loaded relations and you use that relation in the code when it is not fetched, Hibernate will fetch the relation for you if a Hibernate session is opened. This is done with extra queries to the database. If for example the relation is a collection of objects, Hibernate by default will make one query for each entity in the collection, resulting in many queries. In performance sensitive parts of an application where we use a large portion of an entity tree, we might get a huge amount of queries to the database when it should only be one query. This could lead to extreme bottlenecks being introduced. If a Hibernate session is not open you will get a LazyInitializationException instead.
If we have, for example, the following entity structure:

And we have the following code snippet with the assumption that we have an open Hibernate session from start.

TypedQuery query = getEntityManager().createQuery(“from Order where orderId = ” + orderId, Order.class);
Order theOrder = query.uniqueResult();
for (OrderLine orderLine : theOrder.getOrderLines()) {
    System.out.println(orderLine.getInfoText());
}

The above code would generate one SQL query for fetching the Order and one SQL query for each OrderLine for the Order fetched.

Suggestion: Use join fetch in earlier queries to avoid generating unnecessary queries.

In the above example we should write the following code instead:

TypedQuery query = getEntityManager().createQuery(
    “from Order o left join fetch o.orderLines " +
    "where orderId = ” + orderId, Order.class);
Order theOrder = query.uniqueResult();
for (OrderLine orderLine : theOrder.getOrderLines()) {
    System.out.println(orderLine.getInfoText());
}

The difference in the above code is the addition of “left join fetch”. This initialize the collection by adding a “left outer join” to the first SQL query and we only get one query for the whole operation.

Value: We avoid that Hibernate makes a lot of unnecessary queries to the database to fetch lazy relations. This way we optimize how we communicate with the database.

3. Learn to use and activate SQL logging during development

Problem: When working with Hibernate it is easy to just code functionality so that things work and forget thinking about what SQL queries that are actually being generated by Hibernate. This leads to SQL being issued that is not needed or intentional which in turn causes hidden bottlenecks.

Suggestion: When developing a part of the application that involves communication with the database, turn on Hibernates SQL logging (show_sql and format_sql). This way SQL queries that are generated by Hibernate will be logged in a structured way in a log-file or standard out depending on configuration. It is also a good idea to turn SQL logging on when tracing a performance hog.
The generated SQL then need to be analyzed by the developer to ensure that each query is issued on purpose and not be a configuration or coding mistake.

Value: The developer will know what queries that are being generated and will see if a join fetch is needed somewhere if a lot of queries seems unnecessary.
Performance bottlenecks can be found this way and sometimes they are not big enough to be identified on an aggregate level while still slowing down the whole solution.

Read more in the next post Hibernate and JPA guidelines [part 2]



Viewing all articles
Browse latest Browse all 26

Trending Articles