Spring Data JPA — Reference Documentation
Spring Data JPA provides repository support for the Java Persistence API (JPA). It eases development of applications that need to access JPA data sources.
1.1. Project Metadata
- Version control: https://github.com/spring-projects/spring-data-jpa
- Bugtracker: https://github.com/spring-projects/spring-data-jpa/issues
- Release repository: https://repo.spring.io/libs-release
- Milestone repository: https://repo.spring.io/libs-milestone
- Snapshot repository: https://repo.spring.io/libs-snapshot
2. New & Noteworthy
2.1. What’s New in Spring Data JPA 1.11
Spring Data JPA 1.11 added the following features:
- Improved compatibility with Hibernate 5.2.
- Support any-match mode for [query-by-example].
- Paged query optimizations.
- Support for the exists projection in repository query derivation.
2.2. What’s New in Spring Data JPA 1.10
Spring Data JPA 1.10 added the following features:
- Support for [projections] in repository query methods.
- Support for [query-by-example].
- The following annotations have been enabled to build on composed annotations: @EntityGraph , @Lock , @Modifying , @Query , @QueryHints , and @Procedure .
- Support for the Contains keyword on collection expressions.
- AttributeConverter implementations for ZoneId of JSR-310 and ThreeTenBP.
- Upgrade to Querydsl 4, Hibernate 5, OpenJPA 2.4, and EclipseLink 2.6.1.
Unresolved directive in index.adoc — include. /../../../spring-data-commons/src/main/asciidoc/dependencies.adoc[leveloffset=+1]
Unresolved directive in index.adoc — include. /../../../spring-data-commons/src/main/asciidoc/repositories.adoc[leveloffset=+1]
3. Reference Documentation
3.1. JPA Repositories
This chapter points out the specialties for repository support for JPA. This builds on the core repository support explained in “[repositories]”. Make sure you have a sound understanding of the basic concepts explained there.
3.1.1. Introduction
This section describes the basics of configuring Spring Data JPA through either:
Spring Namespace
The JPA module of Spring Data contains a custom namespace that allows defining repository beans. It also contains certain features and element attributes that are special to JPA. Generally, the JPA repositories can be set up by using the repositories element, as shown in the following example:
Using the repositories element looks up Spring Data repositories as described in “[repositories.create-instances]”. Beyond that, it activates persistence exception translation for all beans annotated with @Repository , to let exceptions being thrown by the JPA persistence providers be converted into Spring’s DataAccessException hierarchy.
Custom Namespace Attributes
Beyond the default attributes of the repositories element, the JPA namespace offers additional attributes to let you gain more detailed control over the setup of the repositories:
Explicitly wire the EntityManagerFactory to be used with the repositories being detected by the repositories element. Usually used if multiple EntityManagerFactory beans are used within the application. If not configured, Spring Data automatically looks up the EntityManagerFactory bean with the name entityManagerFactory in the ApplicationContext .
Explicitly wire the PlatformTransactionManager to be used with the repositories being detected by the repositories element. Usually only necessary if multiple transaction managers or EntityManagerFactory beans have been configured. Default to a single defined PlatformTransactionManager inside the current ApplicationContext .
Spring Data JPA requires a PlatformTransactionManager bean named transactionManager to be present if no explicit transaction-manager-ref is defined. |
Annotation-based Configuration
The Spring Data JPA repositories support can be activated not only through an XML namespace but also by using an annotation through JavaConfig, as shown in the following example:
@Configuration @EnableJpaRepositories @EnableTransactionManagement class ApplicationConfig < @Bean public DataSource dataSource() < EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.HSQL).build(); >@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() < HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(true); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan("com.acme.domain"); factory.setDataSource(dataSource()); return factory; >@Bean public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) < JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory); return txManager; >>
You must create LocalContainerEntityManagerFactoryBean and not EntityManagerFactory directly, since the former also participates in exception translation mechanisms in addition to creating EntityManagerFactory . |
The preceding configuration class sets up an embedded HSQL database by using the EmbeddedDatabaseBuilder API of spring-jdbc . Spring Data then sets up an EntityManagerFactory and uses Hibernate as the sample persistence provider. The last infrastructure component declared here is the JpaTransactionManager . Finally, the example activates Spring Data JPA repositories by using the @EnableJpaRepositories annotation, which essentially carries the same attributes as the XML namespace. If no base package is configured, it uses the one in which the configuration class resides.
Bootstrap Mode
By default, Spring Data JPA repositories are default Spring beans. They are singleton scoped and eagerly initialized. During startup, they already interact with the JPA EntityManager for verification and metadata analysis purposes. Spring Framework supports the initialization of the JPA EntityManagerFactory in a background thread because that process usually takes up a significant amount of startup time in a Spring application. To make use of that background initialization effectively, we need to make sure that JPA repositories are initialized as late as possible.
As of Spring Data JPA 2.1 you can now configure a BootstrapMode (either via the @EnableJpaRepositories annotation or the XML namespace) that takes the following values:
- DEFAULT (default) — Repositories are instantiated eagerly unless explicitly annotated with @Lazy . The lazification only has effect if no client bean needs an instance of the repository as that will require the initialization of the repository bean.
- LAZY — Implicitly declares all repository beans lazy and also causes lazy initialization proxies to be created to be injected into client beans. That means, that repositories will not get instantiated if the client bean is simply storing the instance in a field and not making use of the repository during initialization. Repository instances will be initialized and verified upon first interaction with the repository.
- DEFERRED — Fundamentally the same mode of operation as LAZY , but triggering repository initialization in response to an ContextRefreshedEvent so that repositories are verified before the application has completely started.
Recommendations
If you’re not using asynchronous JPA bootstrap stick with the default bootstrap mode.
In case you bootstrap JPA asynchronously, DEFERRED is a reasonable default as it will make sure the Spring Data JPA bootstrap only waits for the EntityManagerFactory setup if that itself takes longer than initializing all other application components. Still, it makes sure that repositories are properly initialized and validated before the application signals it’s up.
LAZY is a decent choice for testing scenarios and local development. Once you are pretty sure that repositories can properly bootstrap, or in cases where you are testing other parts of the application, running verification for all repositories might unnecessarily increase the startup time. The same applies to local development in which you only access parts of the application that might need to have a single repository initialized.
3.1.2. Persisting Entities
This section describes how to persist (save) entities with Spring Data JPA.
Saving Entities
Saving an entity can be performed with the CrudRepository.save(…) method. It persists or merges the given entity by using the underlying JPA EntityManager . If the entity has not yet been persisted, Spring Data JPA saves the entity with a call to the entityManager.persist(…) method. Otherwise, it calls the entityManager.merge(…) method.
Entity State-detection Strategies
Spring Data JPA offers the following strategies to detect whether an entity is new or not:
- Version-Property and Id-Property inspection (default): By default Spring Data JPA inspects first if there is a Version-property of non-primitive type. If there is, the entity is considered new if the value of that property is null . Without such a Version-property Spring Data JPA inspects the identifier property of the given entity. If the identifier property is null , then the entity is assumed to be new. Otherwise, it is assumed to be not new.
- Implementing Persistable : If an entity implements Persistable , Spring Data JPA delegates the new detection to the isNew(…) method of the entity. See the JavaDoc for details.
- Implementing EntityInformation : You can customize the EntityInformation abstraction used in the SimpleJpaRepository implementation by creating a subclass of JpaRepositoryFactory and overriding the getEntityInformation(…) method accordingly. You then have to register the custom implementation of JpaRepositoryFactory as a Spring bean. Note that this should be rarely necessary. See the JavaDoc for details.
Option 1 is not an option for entities that use manually assigned identifiers and no version attribute as with those the identifier will always be non- null . A common pattern in that scenario is to use a common base class with a transient flag defaulting to indicate a new instance and using JPA lifecycle callbacks to flip that flag on persistence operations:
@MappedSuperclass public abstract class AbstractEntity implements Persistable (1) @Override public boolean isNew() (2) > @PrePersist (3) @PostLoad void markNotNew() < this.isNew = false; >// More code… >
1 | Declare a flag to hold the new state. Transient so that it’s not persisted to the database. |
2 | Return the flag in the implementation of Persistable.isNew() so that Spring Data repositories know whether to call EntityManager.persist() or ….merge() . |
3 | Declare a method using JPA entity callbacks so that the flag is switched to indicate an existing entity after a repository call to save(…) or an instance creation by the persistence provider. |
3.1.3. Query Methods
This section describes the various ways to create a query with Spring Data JPA.
Query Lookup Strategies
The JPA module supports defining a query manually as a String or having it being derived from the method name.
Derived queries with the predicates IsStartingWith , StartingWith , StartsWith , IsEndingWith , EndingWith , EndsWith , IsNotContaining , NotContaining , NotContains , IsContaining , Containing , Contains the respective arguments for these queries will get sanitized. This means if the arguments actually contain characters recognized by LIKE as wildcards these will get escaped so they match only as literals. The escape character used can be configured by setting the escapeCharacter of the @EnableJpaRepositories annotation. Compare with Using SpEL Expressions.
Declared Queries
Although getting a query derived from the method name is quite convenient, one might face the situation in which either the method name parser does not support the keyword one wants to use or the method name would get unnecessarily ugly. So you can either use JPA named queries through a naming convention (see Using JPA Named Queries for more information) or rather annotate your query method with @Query (see Using @Query for details).
Query Creation
Generally, the query creation mechanism for JPA works as described in “[repositories.query-methods]”. The following example shows what a JPA query method translates into:
public interface UserRepository extends Repository < ListfindByEmailAddressAndLastname(String emailAddress, String lastname); >
We create a query using the JPA criteria API from this, but, essentially, this translates into the following query: select u from User u where u.emailAddress = ?1 and u.lastname = ?2 . Spring Data JPA does a property check and traverses nested properties, as described in “[repositories.query-methods.query-property-expressions]”.
The following table describes the keywords supported for JPA and what a method containing that keyword translates to:
select distinct … where x.lastname = ?1 and x.firstname = ?2
… where x.lastname = ?1 and x.firstname = ?2
… where x.lastname = ?1 or x.firstname = ?2
findByFirstname , findByFirstnameIs , findByFirstnameEquals
… where x.startDate between ?1 and ?2