Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly.
Hypersistence Optimizer is that tool!
In-memory databases such as H2, HSQLDB, and Derby are great to speed up integration tests. Although most database queries can be run against these in-memory databases, many enterprise systems make use of complex native queries which can only be tested against an actual production-like relational database.
In this post, I’m going to show you how you can run PostgreSQL and MySQL integration tests almost as fast as any in-memory database.
Hibernate uses H2 by default, and, running all tests for the documentation module (317 tests) takes around 46 seconds:
> gradle clean test
Total time: 46.148 secs
Now let’s see how much time it takes to run all these tests on my local MySQL 5.7 database engine:
> gradle clean test -Pdb=mysql
Total time: 30 mins 26.568 secs
MySQL DDL statements are very expensive, and each unit tests creates and destroys a SessionFactory, which, in turn, creates and destroys a database schema. This allows each test to start with a clean state, therefore providing test isolation.
However, by default, all transactions are ACID, and, to ensure Durability, all changes need to be flushed to disk whenever a transaction is completed. Creating and dropping a database schema after each test requires many I/O intensive operations that take a toll on the overall test execution time.
Luckily, for integration tests, we don’t need any Durability guarantee. We only need speed!
That being said, we can move the database data directory onto a RAM disk. On Linux, you can use tempfs, but, because I have a Windows machine, I’m going to use the ImDisk Virtual Disk Driver utility for this purpose.
If you’re interested in speeding up database integration tests with Docker and tmpfs, check out this article. It works on any Operation System (Linux, OSX, Windows), and, even for Windows, it’s much easier to work than with an ImDisk Virtual Disk Driver.
The ImDisk Virtual Disk Driver allows you to map a fragment of the total RAM memory just like a hard disk drive.
The script that does all the work looks like this:
Based on my book, High-Performance Java Persistence, this workshop teaches you various data access performance optimizations from JDBC, to JPA, Hibernate and jOOQ for the major rational database systems (e.g. Oracle, SQL Server, MySQL and PostgreSQL).