The Java Persistence API is a standard technology that allows you to "map" objects to relational databases. The spring-boot-starter-data-jpa POM model allows you to get started quickly. It provides the following key dependencies:

  • Hibernate is one of the most popular JPA implementations.

  • Spring Data JPA: Helps implement JPA-based repositories.

  • Spring ORM: The primary ORM support tool from the Spring Framework.

Traditionally, JPA "entity" classes are defined in the persistence.xml file. In Spring Boot, this file is not required; Entity Scanning is used instead. By default, the search is performed in all packages below the main configuration class (the one annotated with @EnableAutoConfiguration or @SpringBootApplication).

Any classes annotated with @Entity, @Embeddable or @MappedSuperclass are taken into account. A typical entity class looks like the following example:

Java
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class City implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false)
    private String name;
    @Column(nullable = false)
    private String state;
    // ... additional members, often containing @OneToMany annotation mappings
    protected City() {
        // no-argument constructor required by the JPA specification
        // protected because it's not meant to be used directly
    }
    public City(String name, String state) {
        this.name = name;
        this.state = state;
    }
    public String getName() {
        return this.name;
    }
    public String getState() {
        return this.state;
    }
    // ... etc.
}
Kotlin
import java.io.Serializable
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
@Entity
class City : Serializable {
    @Id
    @GeneratedValue
    private val id: Long? = null
    @Column(nullable = false)
    var name: String? = null
        private set
    // ... etc.
    @Column(nullable = false)
    var state: String? = null
        private set
    // ... additional members, often containing @OneToMany annotation mappings
    protected constructor() {
        // no-argument constructor required by the JPA specification
        // protected because it's not meant to be used directly
    }
    constructor(name: String?, state: String?) {
        this.name = name
        this.state = state
    }
}
You can configure the locations to be scanned for entities using the @EntityScan annotation.

Spring Data JPA Repositories

Spring Data JPA repositories are interfaces that can be defined to access data. JPA queries are created automatically based on method names. For example, the CityRepository interface might declare a findAllByState(String state) method to find all cities in a given state.

For more complex queries, you can annotate the method using the Query annotation from Spring Data.

Spring Data repositories are typically extended using the Repository or CrudRepository interfaces. If you use autoconfiguration, the repositories are searched from the package containing the main configuration class (the one annotated with @EnableAutoConfiguration or @SpringBootApplication) and down the hierarchy.

The following example shows a typical interface definition for interacting with a Spring Data repository:

Java
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
public interface CityRepository extends Repository<City, Long> {
    Page<City> findAll(Pageable pageable);
    City findByNameAndStateAllIgnoringCase(String name, String state);
}
Kotlin
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.repository.Repository
interface CityRepository : Repository<City?, Long?> {
    fun findAll(pageable: Pageable?): Page<City?>?
    fun findByNameAndStateAllIgnoringCase(name: String?, state: String?): City?
}

Spring Data JPA repositories support three different bootstrap modes: default, delayed, and lazy. To enable deferred loading or lazy loading, set the spring.data.jpa.repositories.bootstrap-mode property to deferred or lazy respectively. When lazy loading or delayed loading, the autoconfigured EntityManagerFactoryBuilder will use the context's AsyncTaskExecutor, if present, as the load executor. If there is more than one executor, the one named applicationTaskExecutor will be used.

When using delayed loading or lazy loading, you should ensure that access to the JPA infrastructure is provided with a delay after the application context initial loading stage. You can use SmartInitializingSingleton to call any initialization that requires the JPA framework. For JPA components (such as converters) that are instantiated as Spring beans, use ObjectProvider to defer dependency resolution, if any.

Spring Data Envers Repositories

If Spring Data Envers is available, JPA repositories will be automatically configured to support typical Envers queries.

To use Spring Data Envers, ensure that the repository is extended from RevisionRepository, as shown in the following example:

Java
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.history.RevisionRepository;
public interface CountryRepository extends RevisionRepository<Country, Long, Integer>, Repository<Country, Long> {
    Page<Country> findAll(Pageable pageable);
}
Kotlin
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.repository.Repository
import org.springframework.data.repository.history.RevisionRepository
interface CountryRepository :
        RevisionRepository<Country?, Long?, Int>,
        Repository<Country?, Long?> {
    fun findAll(pageable: Pageable?): Page<Country?>?
}

Creating and deleting JPA databases

By default, JPA databases are created automatically only if you use an embedded database (H2, HSQL or Derby). You can explicitly configure JPA settings using the spring.jpa.* properties. For example, to create and delete tables, you can add the following line to application.properties:

Properties
spring.jpa.hibernate.ddl-auto=create-drop
Yaml
spring:
  jpa:
    hibernate.ddl-auto: "create-drop"
The native Hibernate property name for this procedure (if you remember it well, of course) is hibernate.hbm2ddl.auto. You can set it along with other native Hibernate properties using spring.jpa.properties.* (the prefix is removed before adding it to the entity manager). The following line shows an example of setting JPA properties for Hibernate:
Properties
spring.jpa.properties.hibernate[globally_quoted_identifiers]=true
Yaml
spring:
  jpa:
    properties:
      hibernate:
        "globally_quoted_identifiers": "true"

The line in the previous example passes the value true for the hibernate.globally_quoted_identifiers property to the Hibernate entity manager.

By default, DDL execution (or validation) is deferred until the ApplicationContext is launched. There is also a spring.jpa.generate-ddl flag, but it is not used if Hibernate autoconfiguration is active, since the ddl-auto settings are more precise.

Opening EntityManager in a View

If you are running a web application, Spring Boot by default registers OpenEntityManagerInViewInterceptor to apply the Open EntityManager in View pattern to enable lazy loading in web views. If you do not require this operating logic, then you should set spring.jpa.open-in-view to false in application.properties.