After we have declared the required dependencies in our POM file, we have to configure the application context of our Spring application.
This blog post describes how we can configure the persistence layer of a Spring application that uses Spring Data JPA and Hibernate.
Let’s get started.
Additional Reading:
If you are not familiar with Spring Data JPA, you should read the following blog posts before you continue reading this blog post:
- Spring Data JPA Tutorial: Introduction provides a quick introduction to Spring Data JPA and gives an overview of the Spring Data repository interfaces.
- Spring Data JPA Tutorial: Getting the Required Dependencies describes how you can get the required dependencies.
Configuring the Persistence Layer of a Spring Application
We can create the configuration class, which configures the persistence layer of a Spring application, by following these steps:
- Create the properties file that contains the properties used by our application context configuration class.
- Configure the datasource bean.
- Configure the entity manager factory bean.
- Configure the transaction manager bean.
- Enable annotation-driven transaction management.
- Configure Spring Data JPA.
But before we can get started, we have to create the configuration class that configures the persistence layer of our application. The source code of the PersistenceContext class looks as follows:
1@Configuration
2class PersistenceContext {
3
4 //Configure the required beans here
5}
Let’s start by creating the properties file.
Creating the Properties File
Often we want to use a slightly different configuration in different environments. A good way to do this is move the configuration to a properties file and use a different properties file in different environments.
The application.properties file contains the configuration that is used to configure our example application. We can create this properties file by following these steps:
- Configure the database connection of our application. We need to configure the name of the JDBC driver class, the JDBC url, the username of the database user, and the password of the database user.
- Configure Hibernate by following these steps:
- Configure the used database dialect.
- Ensure that Hibernate creates the database when our application is started and drops it when our application is closed.
- Configure the naming strategy that is used when Hibernate creates new database objects and schema elements.
- Configure the Hibernate to NOT write the invoked SQL statements to the console.
- Ensure that if Hibernate writes the SQL statements to the console, it will use prettyprint.
The application.properties file looks as follows:
1#Database Configuration
2db.driver=org.h2.Driver
3db.url=jdbc:h2:mem:datajpa
4db.username=sa
5db.password=
6
7#Hibernate Configuration
8hibernate.dialect=org.hibernate.dialect.H2Dialect
9hibernate.hbm2ddl.auto=create-drop
10hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
11hibernate.show_sql=false
12hibernate.format_sql=true
The properties found from the application.properties file are loaded by the ExampleApplicationContext class. If you want to take a closer look at it, you can get it from Github.
Additional Reading:
Let’s move on and configure the datasource bean.
Configuring the Datasource Bean
We can configure the datasource bean by following these steps:
- Ensure that the close() method of the created DataSource object is invoked when the application context is closed.
- Configure the database connection. We need to set the name of the JDBC driver class, the JDBC url, the username of database user, and the password of the database user.
- Create a new HikariDataSource object and return the created object.
The method that configures the datasource bean looks as follows:
1@Configuration
2class PersistenceContext {
3
4 @Bean(destroyMethod = "close")
5 DataSource dataSource(Environment env) {
6 HikariConfig dataSourceConfig = new HikariConfig();
7 dataSourceConfig.setDriverClassName(env.getRequiredProperty("db.driver"));
8 dataSourceConfig.setJdbcUrl(env.getRequiredProperty("db.url"));
9 dataSourceConfig.setUsername(env.getRequiredProperty("db.username"));
10 dataSourceConfig.setPassword(env.getRequiredProperty("db.password"));
11
12 return new HikariDataSource(dataSourceConfig);
13 }
14
15 //Add the other beans here
16}
Additional Reading:
Let’s move on and configure the entity manager factory bean.
Configuring the Entity Manager Factory Bean
We can configure the entity manager factory bean by following these steps:
- Create a new LocalContainerEntityManagerFactoryBean object. We need to create this object because it creates the JPA EntityManagerFactory.
- Configure the used datasource.
- Configure the Hibernate specific implementation of the JpaVendorAdapter interface. It will initialize our configuration with the default settings that are compatible with Hibernate.
- Configure the packages that are scanned for entity classes.
- Configure the JPA properties that are used to provide additional configuration to the used JPA provider.
The method that configures the entity manager factory bean looks as follows:
1@Configuration
2class PersistenceContext {
3
4 @Bean
5 LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
6 Environment env) {
7 LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
8 entityManagerFactoryBean.setDataSource(dataSource);
9 entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
10 entityManagerFactoryBean.setPackagesToScan("net.petrikainulainen.springdata.jpa.todo");
11
12 Properties jpaProperties = new Properties();
13
14 //Configures the used database dialect. This allows Hibernate to create SQL
15 //that is optimized for the used database.
16 jpaProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
17
18 //Specifies the action that is invoked to the database when the Hibernate
19 //SessionFactory is created or closed.
20 jpaProperties.put("hibernate.hbm2ddl.auto",
21 env.getRequiredProperty("hibernate.hbm2ddl.auto")
22 );
23
24 //Configures the naming strategy that is used when Hibernate creates
25 //new database objects and schema elements
26 jpaProperties.put("hibernate.ejb.naming_strategy",
27 env.getRequiredProperty("hibernate.ejb.naming_strategy")
28 );
29
30 //If the value of this property is true, Hibernate writes all SQL
31 //statements to the console.
32 jpaProperties.put("hibernate.show_sql",
33 env.getRequiredProperty("hibernate.show_sql")
34 );
35
36 //If the value of this property is true, Hibernate will format the SQL
37 //that is written to the console.
38 jpaProperties.put("hibernate.format_sql",
39 env.getRequiredProperty("hibernate.format_sql")
40 );
41
42 entityManagerFactoryBean.setJpaProperties(jpaProperties);
43
44 return entityManagerFactoryBean;
45 }
46
47 //Add the other beans here
48}
Additional Reading:
- The Javadoc of the EntityManagerFactory interface
- The Javadoc of the LocalContainerEntityManagerFactoryBean class
- The Javadoc of the JpaVendorAdapter interface
- The Javadoc of the HibernateJpaVendorAdapter class
- Spring Framework Reference Manual: 15.5.1 Three options for JPA setup in a Spring environment
- Hibernate ORM Reference Manual: 3.4. Optional configuration properties
Let’s move on and configure the transaction manager bean.
Configuring the Transaction Manager Bean
Because we are using JPA, we have to create a transaction manager bean that integrates the JPA provider with the Spring transaction mechanism. We can do this by using the JpaTransactionManager class as the transaction manager of our application.
We can configure the transaction manager bean by following these steps:
- Create a new JpaTransactionManager object.
- Configure the entity manager factory whose transactions are managed by the created JpaTransactionManager object.
The method that configures the transaction manager bean looks as follows:
1@Configuration
2class PersistenceContext {
3
4 @Bean
5 JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
6 JpaTransactionManager transactionManager = new JpaTransactionManager();
7 transactionManager.setEntityManagerFactory(entityManagerFactory);
8 return transactionManager;
9 }
10
11 //Add the other beans here
12}
Additional Reading:
Let’s move on and enable annotation-driven transaction management.
Enabling Annotation-Driven Transaction Management
We can enable annotation-driven transaction management by annotating the PersistenceContext class with the @EnableTransactionManagement annotation. The relevant part of the PersistenceContext class looks as follows:
1@Configuration
2@EnableTransactionManagement
3class PersistenceContext {
4
5 //The beans are configured here
6}
Additional Reading:
Let’s move on and configure Spring Data JPA.
Configuring Spring Data JPA
We can configure Spring Data JPA by following these steps:
- Enable Spring Data JPA by annotating the PersistenceContext class with the @EnableJpaRepositories annotation.
- Configure the base packages that are scanned when Spring Data JPA creates implementations for our repository interfaces.
The relevant part of the PersistenceContext class looks as follows:
1@Configuration
2@EnableJpaRepositories(basePackages = {
3 "net.petrikainulainen.springdata.jpa.todo"
4})
5@EnableTransactionManagement
6class PersistenceContext {
7
8 //The beans are configured here
9}
Additional Reading:
That is all folks. We have now successfully configured the persistence layer of our example application. Let’s move on and summarize what we learned from this blog post.
Summary
This blog post has taught us two things:
- If we need to use a different configuration in different environment, we should move this configuration to a properties file.
- We learned to configure the persistence layer of a Spring application that uses Spring Data JPA and Hibernate.
The next part of this tutorial describes how we can create a Spring Data JPA repository that provides CRUD operations for a simple entity.
P.S. You can get the example application of this blog post from Github.