
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: October 27, 2023
This tutorial shows how to set up Spring with JPA, using Hibernate as a persistence provider.
See this article for a step-by-step introduction to setting up the Spring context using Java-based configuration and the basic Maven pom for the project.
We’ll start by setting up JPA in a Spring Boot project. Then we’ll look into the full configuration we need if we have a standard Spring project.
The Spring Boot project is intended to make creating Spring applications much faster and easier. This is done using starters and auto-configuration for various Spring functionalities, JPA among them.
To enable JPA in a Spring Boot application, we need the spring-boot-starter and spring-boot-starter-data-jpa dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.1.0</version>
</dependency>
The spring-boot-starter contains the necessary auto-configuration for Spring JPA. Also, the spring-boot-starter-jpa project references all the necessary dependencies, such as hibernate-core.
Spring Boot configures Hibernate as the default JPA provider, so it’s no longer necessary to define the entityManagerFactory bean unless we want to customize it.
Spring Boot can also auto-configure the dataSource bean, depending on the database we’re using. In the case of an in-memory database of type H2, HSQLDB and Apache Derby, Boot automatically configures the DataSource if the corresponding database dependency is present on the classpath.
For example, if we want to use an in-memory H2 database in a Spring Boot JPA application, we only need to add the h2 dependency to the pom.xml file:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
This way, we don’t need to define the dataSource bean, but we can if we want to customize it.
If we want to use JPA with MySQL database, we need the mysql-connector-java dependency. We’ll also need to define the DataSource configuration.
We can do this in a @Configuration class or by using standard Spring Boot properties.
The Java configuration looks the same as it does in a standard Spring project:
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("mysqluser");
dataSource.setPassword("mysqlpass");
dataSource.setUrl(
"jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true");
return dataSource;
}
To configure the data source using a properties file, we have to set properties prefixed with spring.datasource:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=mysqluser
spring.datasource.password=mysqlpass
spring.datasource.url=
jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true
Spring Boot will automatically configure a data source based on these properties.
Also, in Spring Boot 1, the default connection pool was Tomcat, but it has been changed to HikariCP with Spring Boot 2.
We have more examples of configuring JPA in Spring Boot in the GitHub project.
As we can see, the basic JPA configuration is fairly simple if we’re using Spring Boot.
However, if we have a standard Spring project, we need a more explicit configuration using Java or XML. That’s what we’ll focus on in the next sections.
To use JPA in a Spring project, we need to set up the EntityManager.
This is the main part of the configuration, and we can do it via a Spring factory bean. This can be either the simpler LocalEntityManagerFactoryBean or, the more flexible LocalContainerEntityManagerFactoryBean.
Let’s see how we can use the latter option:
@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.baeldung.persistence.model");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
// ...
}
We also need to explicitly define the DataSource bean we’ve used above:
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_jpa");
dataSource.setUsername( "tutorialuser" );
dataSource.setPassword( "tutorialmy5ql" );
return dataSource;
}
The final part of the configuration is the additional Hibernate properties and the TransactionManager and exceptionTranslation beans:
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
Usually, JPA defines a persistence unit through the META-INF/persistence.xml file. Starting with Spring 3.1, the persistence.xml is no longer necessary. The LocalContainerEntityManagerFactoryBean now supports a packagesToScan property where the packages to scan for @Entity classes can be specified.
This file was the last piece of XML we need to remove. We can now set up JPA fully with no XML.
We would usually specify JPA properties in the persistence.xml file.
Alternatively, we can add the properties directly to the entity manager factory bean:
factoryBean.setJpaProperties(this.additionalProperties());
As a side note, if Hibernate is the persistence provider, this would be the way to specify Hibernate-specific properties as well.
In addition to the Spring Core and persistence dependencies — shown in detail in the Spring with Maven tutorial — we also need to define JPA and Hibernate in the project as well as a MySQL connector:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.5.2.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
<scope>runtime</scope>
</dependency>
Note that the MySQL dependency is included here as an example. We need a driver to configure the data source, but any Hibernate-supported database will do.
Let’s see Spring Data JPA in action with an example project.
First, let’s create a new entity class:
@Entity
public class Publishers {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String location;
private int journals;
// constructors, getters and setters
}
Here, we create an Entity class named Publishers representing a database table, the fields represent columns in the database. In this case, we have four columns and id is the primary key.
The Spring Data JPA provides repository support to perform various database operations without boilerplate code. A repository serves as a link between an entity and the database.
Let’s create a PublisherRepository interface:
public interface PublisherRepository extends JpaRepository<Publishers, Integer> {
}
The repository interface extends the JpaRepository which provides various inbuilt methods for database operation. The common method includes:
Also, Spring Data JPA allows us to derive queries through methods by following a specific naming convention:
public interface PublisherRepository extends JpaRepository<Publishers, Integer> {
List<Publishers> findAllByLocation(String location);
}
In the code above, we define a method named findAllByLocation(). When this method is invoked on a PublisherRepository object, it’s parsed and converted to an SQL query. The findAllBy prefix indicates the start of the query, and the Location indicates the property name corresponding to the location field in the entity class.
Also, we can use the @Query annotation to define a custom query:
@Query("SELECT p FROM Publishers p WHERE p.journals > :minJournals AND p.location = :location")
List<Publisher> findPublishersWithMinJournalsInLocation(Integer minJournals,String location);
Here, we define a query to find all Publishers based on a specific number of journals and locations.
Furthermore, let’s create a service class to implement different logic for a typical database operation.
First, let’s inject the PublisherRepository into the service class:
@Service
class PublisherService {
private final PublisherRepository publisherRepository;
public PublisherService(PublisherRepository publisherRepository) {
this.publisherRepository = publisherRepository;
}
// ...
}
Next, let’s create a method to insert publishers record into the database:
public Publishers save(Publishers publishers) {
return publisherRepository.save(publishers);
}
Here, we use the save() method to persist an entity in the database. It can either save a new entity or update an existing one, depending on whether the entity already exists in the database.
Then, let’s find all the saved publishers:
public List<Publishers> findAll() {
return publisherRepository.findAll();
}
The findAll() method retrieves all publisher’s records in the database and returns them as a List.
Also, let’s find a publisher by its id:
public Publishers findById(int id) {
return publisherRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Publisher not found"));
}
The method above retrieves a publisher record from the database based on the provided id. If no record matches the provided id, it throws a RuntimeException.
Also, let’s use the repository method with the custom query findPublishersWithMinJournalsLocation(). It helps to find publishers based on a minimum number of journals and location:
List<Publishers> findPublishersWithMinJournalsInLocation(int minJournals, String location) {
return publisherRepository.findPublishersWithMinJournalsInLocation(minJournals, location);
}
Now that we have defined methods for different database operations, we can use them in our test class or in a controller.
In this article, we learned how to configure JPA with Hibernate in a Spring boot and a standard Spring application. Also, we saw an example Spring Boot project that persist entities and as well as retrieve entities from the database.
Follow the Spring Category