When developing a Spring Boot application is easy, tuning the performance of a Spring Boot application is a more challenging task, as, not only it requires to understand how the Spring framework works behind scenes, but you have to know is the best way to use underlying data access framework, like Hibernate for instance. we are going to switch underlying database from in-memory HSQLDB to MySQL and run Hypersistence Optimizer to generate the performance tuning report for JPA and Hibernate data access layer in the context of MySQL database.
By default, Spring Boot uses the HSQLDB, but while this in-memory database is used extensively for the testing, in the production environment, you are more likely to use the database like MySQL or PostgreSQL.Luckily, Spring Boot offers the MySQL configuration and the Spring profile, which we can use as a starting point for the analysis.
Switching tests to using a MySQL profile
First of all, we need to use a @ActiveProfiles annotation to activate a mysql Spring profile.
@RunWith(SpringRunner.class) @SpringBootTest @ActiveProfiles("mysql") public class Tests { @PersistenceUnit private EntityManagerFactory entityManagerFactory; @Autowired private VetRepository vets; @Before public void init() { new HypersistenceOptimizer( new JpaConfig(entityManagerFactory) ).init(); } @Test public void testFindAll() throws Exception { vets.findAll(); vets.findAll(); } }
After activating a MySQL Spring profile, Spring Boot is going to use an application-MySQL. properties configuration file to override settings from a default application.properties settings file.
In our case, the only change that was needed in an application-MySQL. the properties configuration file was to change the database connection credentials:
database=mysql spring.datasource.url=jdbc:mysql://localhost/test spring.datasource.username=mysql spring.datasource.password=admin
Running Hypersistence Optimizer
As you can see in a Tests class, running Hypersitence Optimizer is very easy, as you just have to pass an EntityManagerFactory instance to a HypersistenceOptimizer object constructor, and call a init method.
By providing the MySQL-specific orm.xml JPA configuration file that overrides a base class entity identifier strategy, we can switch to using IDENTITY when using MySQL.
So, we are going to create an orm.xml file that's going to be deployed by a MySQL profile in the META-INF folder in the application jar file.
The orm.xml configuration file looks as follows:
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd" version="2.2"> <mapped-superclass class="org.springframework.samples.petclinic.model.BaseEntity"> <attributes> <id name="id"> <generated-value strategy="IDENTITY"/> </id> </attributes> </mapped-superclass> </entity-mappings>
Now, when rerunning test case, Hypersistence Optimizer will generate the following report:
Hypersistence Optimizer : MAJOR - PostInsertGeneratorEvent -
The [id] identifier attribute in the [org.springframework.samples.test] entity uses a [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts.
/#PostInsertGeneratorEvent
Hypersistence Optimizer : MAJOR - PostInsertGeneratorEvent -
The [id] identifier attribute in the [org.springframework.samples.test] entity uses a [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts.
But since we don't really have an option for a PostInsertGeneratorEvent when using MySQL, we can simply choose to ignore this event in our case.
Filtering Hyperstistence Optimizer events
Hypersitence Optimizer is very flexible. You can customize how events are handled, whether you want them to be logged or collected to List, and you can choose to filter events as well.
To filter out a PostInsertGeneratorEvent, you need to configure Hyperstistence Optimizer[] like this:
@Before public void init() { new HypersistenceOptimizer( new JpaConfig(entityManagerFactory) .setEventFilter( event -> !(event instanceof PostInsertGeneratorEvent) ) ).init(); }
Now, when rerunning test case, Hypersistence Optimizer will prevent a PostInsertGeneratorEvent from being included in the report:
Hypersistence Optimizer : MAJOR - DialectVersionEvent -
Your application is using a [org.hibernate.dialect.MySQL5Dialect] Hibernate-specific Dialect. Consider using a [org.hibernate.dialect.MySQL57Dialect] instead as it's closer to your current database server version [MySQL 8.0].
/#DialectVersionEvent
DialectVersionEvent
The DialectVersionEvent is generated because the default configured Hibernate dialect is MySQL57Dialect while an application is running against MySQL 8.
So, we just have to include the MySQL8Dialect in a Spring Boot application-MySQL. properties configuration file:
database=mysql spring.datasource.url=jdbc:mysql://localhost/petclinic spring.datasource.username=mysql spring.datasource.password=admin spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
Hypersistence Optimizer is a very powerful tool that can help you detect JPA and Hibernate performance issues long before they hit a production system. And, one of its greatest advantages is that it can do all these checks on commit, so you will no longer overlook the JPA or Hibernate performance-related improvement because of the very tight development schedule.