Spring Data JPA: Difference between revisions
Line 150: | Line 150: | ||
=Database Access Configuration= | =Database Access Configuration= | ||
* [[Spring_H2_Support#Database_Access_Configuration|H2 Database Access Configuration]] | |||
=Database Initialization= | =Database Initialization= |
Revision as of 18:17, 31 October 2018
External
- https://spring.io/projects/spring-data-jpa
- Spring Data Core JavaDoc https://docs.spring.io/spring-data/commons/docs/current/api/
- Spring Data JPA JavaDoc https://docs.spring.io/spring-data/jpa/docs/current/api/
Internal
Overview
Spring Data JPA is a Spring Data project that assists with implementing JPA-based repositories, which persist data in relational databases. The approach involves writing the repository interface, including custom finder methods, and Spring will provide the implementation automatically.
Spring Persistence Concepts
Spring Boot Support
Playground Examples
Working examples for H2, and both H2 and PostgreSQL is available here:
Spring Boot Starter Dependencies
To add support for Spring Data JPA to a Spring Boot project, add the following starter dependency:
dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
}
This starter dependency also transitively includes Hibernate as the JPA implementation.
Add Specific Database Support
Spring Data JPA needs a database to work with. The database drivers should be bundled with the application and should be available on its classpath. Spring Boot does that if its build system is configured with the right dependencies, as shown below:
Configure Database Access
Adding Persistence to an Application with Spring Data JPA
Annotate Domain Objects with @Entity
Annotate your domain objects that require persistence with @Entity and designate their primary key field with @Id and optionally with @GeneratedValue. JPA requires each entity class to expose a no-argument constructor, which can be coded manually, or it can be generated with Lombok's @NoArgConstructor:
@NoArgConstructor(access=AccessLevel.PRIVATE, force=true)
From a project layout perspective, we conventionally maintain the classes in a "model" package.
Entity Member Variable Conventions
- Camel-case member variables map by default on '_' separated column names. "createdAt" maps to a "created_at" column.
Define Relationships between Entities
@ManyToMany, etc.
Declare the JPA Repositories
Entities are built, managed and exposed to the application by JPA repositories. JPA repositories are explicitly declared by the application. A Spring Data JPA repository is the embodiment of the Spring repository concept concept. Similarly to a JdbcTemplate-based repository, a JPA repository conceals low-level data access details from the application while exposing Entities to the application. With JdbcTemplate-based repositories the developers need to explicitly declare and implement the methods that should be exposed by the repository, such as findOne(...), findAll() and save(...). With Spring Data JPA repositories, it is sufficient to extend the CrudRepository interface, which already comes with essential methods. Note that similarly to the JdbcTemplate-based repository, it is a good idea to define the repository as an interface in the application domain:
public interface IngredientRepository extends CrudRepository<Ingredient, String> {
}
Unlike JdbcTemplate-based repositories, the developer does NOT need to provide an implementation of the repository interface. Spring Data JPA automatically generates an implementation. All that is needed to be done is to inject the repositories into controllers and other components that need them.
If the default methods are not sufficient, JPA repositories can be customized.
From a project layout perspective, we conventionally maintain the repository interfaces in a "repository" package.
CrudRepository
CrudRepository declares about a dozen methods for CRUD (create, read, update, delete) operations. It is type-parameterized, with the first parameter being the entity type of the repository, and the second parameter being the type of the entity ID property.
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
}
Customizing JPA Repositories
Additional methods can be added to the Spring Data JPA repository interface. Spring Data examines any method in the repository interface, parses the method name and attempts to understand the method's purpose in the context of the persisted entity. In essence, Spring Data understands a meta-domain-specific language (DSL) where persistence details are expressed in repository method signatures. In order to be interpretable, repository methods must be composed of a verb, an optional subject, the word "By", and a predicate. If the subject is not specified, it is implied to be the entity associated with the repository.
To fetch one or more entities, use "get", "find" or "read" as verb. To count, use "count".
The subject, if it specified and it is not the type the repository is parameterized with, will be ignored.
The predicate signature may include any of these operators:
- IsAfter, After, IsGreaterThan, GreaterThan
- IsGreaterThanEqual, GreaterThanEqual
- IsBefore, Before, IsLessThan, LessThan
- IsLessThanEqual, LessThanEqual
- IsBetween, Between
- IsNull, Null
- IsNotNull, NotNull
- IsIn, In
- IsNotIn, NotIn
- IsStartingWith, StartingWith, StartsWith
- IsEndingWith, EndingWith, EndsWith
- IsContaining, Containing, Contains
- IsLike, Like
- IsNotLike, NotLike
- IsTrue, True
- IsFalse, False
- Is, Equals
- IsNot, Not
- IgnoringCase, IgnoresCase
As alternatives for "IgnoringCase" and "IgnoresCase", "AllIgnoringCase" or "AllIgnoresCase" can be placed in the method name to ignore case for all String comparisons.
"OrderBy" can be placed at the end of the method name to sort the results by a specified column.
Complex queries can be added with the @Qyery annotation:
@Query("Something s where o.name='blah'")
List<Something> getSomeSomethings();
Database Access Configuration
Database Initialization
Also see:
Generic JPA Database Initialization
JPA can generate DDL in the database at startup. The feature is controlled by the configuration property spring.jpa.generate-ddl (true or false), which switches the feature on and off and it is vendor independent. The configuration property is conventionally placed in application.properties or application.yml.
Database Initialization Using Hibernate
Controlled by spring.jpa.hibernate.ddl-auto. Can be "none", "validate", "update", "create" and "create-drop".
If Hibernate creates the schema from scratch and finds a file named import.sql in the root of the classpath, it will execute it against the database.
The configuration property is conventionally placed in application.properties or application.yml.
Configuration
spring.jpa.show-sql=true
TODO
- How to tell that a JPA repository should use a specific database. How is that configured?
- @EnableJpaRepositories(basePackages = "com.example.dev.myproject.driver.repo")