Hibernate Application Performance Tuning
Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?
What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?
Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.
So, rather than fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend your time on the things that you love!
Introduction
Because performance tuning is very important when it comes to developing a data access layer, in this article, I’m going to show you how you can optimize the famous Hibernate Caveat Emptor application using Hypersistence Optimizer.
The Caveat Emptor application was created by Christian Bauer and Gavin King for the Hibernate in Action book they published in 2004 and was included in both the first and second editions of the well-known Java Persistence with Hibernate book.
Getting the Caveat Emptor application
You can get all three versions of the Caveat Emptor application from the Java Persistence with Hibernate website.
For this article, I chose the 2006 Caveat Emptor native Hibernate version and wanted to see if I could run Hypersistence Optimizer to detect performance issues.
Now, since Hypersistence Optimizer requires at least Hibernate 3.3, I had to make several dependency upgrades in order to run my test:
hibernate3.jar⇢hibernate-core-3.3.0.GA.jarcommons-collections-2.1.1.jar⇢commons-collections-3.2.2.jartestng-5.4-jdk15.jar⇢testng-6.14.3.jarjboss-common.jar⇢slf4j-api-1.6.1.jarandslf4j-log4j12-1.6.1.jar
And I added the following dependencies:
javax-jpa-1.0.jarhypersistence-optimizer-2.4.0.jar
And, that’s it!
Adding a Hibernate application performance tuning test
Now, to analyze the performance issues of the Caveat Emptor application, I created the following integration test:
public class PerformanceTuningTest
extends HibernateIntegrationTest {
protected void prepareSettings() {
dataSetLocation = "auction/test/basedata.xml";
beforeTestOperations.add(
DatabaseOperation.CLEAN_INSERT
);
}
@Test(groups = "integration-hibernate")
public void checkPerformanceIssues() {
List<Event> events = new HypersistenceOptimizer(
new HibernateConfig(
HibernateUtil.getSessionFactory()
)
).getEvents();
Assert.assertTrue(events.isEmpty());
}
}
And, when running this integration test, I got the following outcome:
Hypersistence Optimizer - 47 issues were found: - 1 BLOCKER, - 31 CRITICAL, - 5 MAJOR, - 10 MINOR
Of all those issues, 40 are mapping-related issues:
- 12
IdentityGeneratorEvent - 9
IntegerVersionColumnSizeEvent - 7
EagerFetchingEvent - 4
BidirectionalSynchronizationEvent - 2
UnidirectionalOneToManyEvent - 2
ElementCollectionEvent - 1
ElementCollectionListEvent - 1
StringDiscriminatorTypeEvent - 1
BatchFetchingEvent
And 7 are configuration-related problems:
- 1
DriverManagerConnectionProviderEvent - 1
MultiLineStatementLoggingEvent - 1
SqlCommentStatementLoggingEvent - 1
JdbcBatchOrderInsertsEvent - 1
JdbcBatchOrderUpdatesEvent - 1
JdbcBatchVersionedEntitiesEvent - 1
SchemaGenerationEvent
IdentityGeneratorEvent
The IdentityGeneratorEvent is reported as follows:
CRITICAL - IdentityGeneratorEvent - The [id] identifier attribute in the [ItemEntity] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Consider using the SEQUENCE identifier strategy instead.
If we go to the ItemEtity, we can see that, indeed, the id is mapped like this:
<!ENTITY idgenerator "identity">
<id name="id" type="long" column="ITEM_ID" node="@id">
<generator class="&idgenerator;"/>
</id>
Using the
IDENTITYgenerator is not recommended if the underlying database supports sequences since you won’t be able to benefit from automatic batch inserts.
EagerFetchingEvent
The EagerFetchingEvent is reported like this:
CRITICAL - EagerFetchingEvent - The [deliveryAddress] attribute in the [Shipment] entity uses eager fetching. Consider using lazy fetching, which not only that is more efficient, but is way more flexible when it comes to fetching data.
The deliveryAddress association in the Shipment entity is mapped like this:
<many-to-one name="deliveryAddress"
class="AddressEntity"
column="DELIVERY_ADDRESS_ID"
not-null="true"
update="false"
fetch="join"
foreign-key="FK_DELIVERY_ADDRESS_ID"
/>
Because the fetch attribute is set to the join strategy, this association is going to be fetched eagerly every time the Shipment is loaded, even when we don’t need this association.
Using eager fetching mappings is not recommended because this can lead to very serious performance issues. Not only that the associations will be fetched even when they are not needed, but they can cause N+1 query issues as well.
For more details about this topic, check out this article.
BidirectionalSynchronizationEvent
The BidirectionalSynchronizationEvent is reported like this:
CRITICAL - BidirectionalSynchronizationEvent - The [categorizedItems] bidirectional association in the [Item] entity requires both ends to be synchronized. Consider adding the [addCategorizedItem(CategorizedItem categorizedItem)] and [removeCategorizedItem(CategorizedItem categorizedItem)] synchronization methods.
Indeed, if you navigate the Item, you’ll see that it doesn’t contain the addCategorizedItem and removeCategorizedItem methods.
Not synchronizing both sides of a bidirectional association is not recommended since Hibernate doesn’t guarantee that the entity state transitions will propagate properly.
For more details about this topic, check out this article.
Cool, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
Hypersistence Optimizer is a very versatile tool. Not only that it works with Spring Boot, Spring, Jakarta EE, Java EE, Play, or other frameworks, but you can use it even with legacy applications that are using very old Hibernate versions.
If you want to speed up your data access layer, Hypersistence Optimizer will surely help you achieve your goal. And, not only will it detect current issues, but you can use it to prevent those issues from ever happening again via an automated integration test that checks that no issue is being detected.


