1 JPA

JPA, which stands for Java Persistence API (Java Persistence Layer API), is a Java Persistence specification introduced in JDK 5. It provides developers with an object/association mapping tool to manage relational data in applications, simplifying persistence of Java objects. Many ORM frameworks implement JPA specifications, such as Hibernate, EclipseLink, etc.

1.1 Java Persistence Layer Framework

The Java persistence layer framework accesses databases in two ways. An SQL-based framework that encapsulates a certain degree of JDBC operations, such as MyBatis framework. The other is based on Java entity class as the core, to establish the mapping relationship between entity class and database table, that is, ORM framework, such as Hibernate, Spring Data JPA.

1.2 the JPA specification

  1. ORM mapping metadata: JPA supports XML and annotations as metadata forms. Metadata is used to describe the mapping between objects and tables from which the framework persists entity objects to database tables.

  2. JPA API: used to manipulate entity objects and perform CRUD operations. For simple CRUD operations, developers don’t have to write code.

  3. JPQL query language: Query data in an object-oriented manner.

1.3 the Hibernate

Hibernate framework can map data model objects in an application to relational database tables.

JPA is the specification, and Hibernate is an implementation framework for JPA.

2 Spring Data JPA

Spring Data JPA is a set of JPA application framework encapsulated on the basis of implementing the JPA specification. Spring Data JPA makes it easy to switch between different ORM frameworks without changing the code. The goal of the Spring Data JPA is to unify the ORM framework’s access persistence layer operations to improve development efficiency.

The Spring Data JPA is just an abstraction layer, designed to reduce the amount of boilerplate code required to implement a Data access layer for various persistence tier stores. Its JPA implementation layer is implemented using Hibernate framework.

2.1 Importing dependent packages

In a Spring Boot application, simply open pom.xml and add a Spring Data JPA dependency. This dependency not only introduces Spring Data JPA, but also transitively introduces Hibernate as a JPA implementation.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Copy the code

2.2 Entity Class annotations

(1) @ the Entity

Class annotation that identifies the entity class as a JPA entity.

(2) @table (name = “custom Table name”)

Class annotation, used to customize the table name of the entity class in the database. Default is the entity class name. In particular, this annotation is used to specify table names for entity class names that are used as database keywords.

(3) @ Id

Class variable annotations that specify the primary key.

(4) @ GeneratedValue

Class variable annotations that specify the primary key generation strategy.

It contains the strategy attribute, as described below:

strategy instructions
AUTO Controlled by program, default option
IDENTITY Generated in database self-growth mode for MySQL
SEQUENCE Generated by a database sequence, applicable to Oracle
Table Generated by the specified table

(5) @ Basic

Specifies the mapping between class variable reading methods and database table fields. For the getXxxx() method without any special annotations, the @basic annotation is the default. That is, except in special cases, all class variables are annotated @BASIC, and these variables are mapped to the specified table field.

The @BASIC annotation has a fetch attribute for the read strategy. There are two types of EAGER and LAZY policies, which are represented as active reads and LAZY loads respectively. The default value is EAGER.

(6) @ the Column

A description of a column, which may be omitted if the field name is the same as the column name.

The @column annotation has the following properties:

attribute instructions
name The name of the corresponding field in the database table.
length Length of field. This parameter is valid only when the field type is vARCHAR. The default value is 255 characters.
nullable Whether the value can be null. The default is true.
Precision and scale Denotes precision. When the field type is double, precision denotes the total length of the value, and scale denotes the number of decimal places.

(7) @ Transient

Class variable annotation indicating that the variable is not a field mapping to a database table. Because the default annotation for a class variable is @basic, this annotation is used for nonpersistent class variables in some scenarios.

(8) @ Temporal

Class variable annotations (also available on the getXxx method) that represent the time format. Specific instructions are as follows:

grammar instructions
@Temporal(TemporalType.DATE) The date, in the form of 2020-10-10
@Temporal(TemporalType.TIME) Time is like 10:10:10
@Temporal(TemporalType.TIMESTAMP) The default value; Date + time, in the form of 2020-10-10 10:10:10

Craig Walls gives an example of entity class code like this:

@Data
@RequiredArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@Entity
public class Ingredient {
    @Id
    private final String id;
    private final String name;
    private final Type type;

    public static enum Type {
        WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
    }
}
Copy the code

In addition to applying the @Entity and @ID annotations, the example adds the @NoargsConstructor annotation at the class level. Because JPA requires an entity class to provide a no-argument constructor, Lombok’s @Noargsconstructor annotation is used to generate this constructor.

The @noargsconstructor annotation can also privatize the no-argument constructor (access = accesslevel.private) so that it cannot be called directly from outside.

Since the variables ID, name, and type of this class are not initialized, we also need to set force to true and initialize it to NULL.

Although the @data annotation would add a parametrated constructor for us, the parametrated constructor is gone because the @noargsconstructor annotation was added earlier. Therefore, an additional @requiredargsConstructor annotation must be added to force the generation of a parameter constructor.

2.3 Entity class relationship annotations

Spring Data JPA has four relational annotations, which are @onetoone, @onetomany, @ManyToOne, and @Manytomany.

These four relational annotations all have fetch and CASCADE attributes.

The fetch property is used to specify the data lazy-loading policy:

strategy instructions
FetchType.LAZY The default value; Lazy loading
FetchType.EAGER Immediately load

The cascade property is used to specify the cascade policy:

strategy instructions
CascadeType.PERSIST Cascading persistence; When the parent entity is saved, the child entity is also saved.
CascadeType.MERGE Level union; Modified child entity to save child entity when parent entity is saved (common).
CascadeType.REMOVE Cascading deletion; When the parent entity is deleted, the associated child entities are deleted in cascade.
CascadeType.REFRESH Cascade refresh; Fetching the parent entity also retrieves the latest child entity.
CascadeType.ALL These four strategies
There is no The default value

Because these four annotations can only represent one-to-one relationships between entities, you need to use the @JoinColumn annotation to specify column fields in the database table associated with the entity being manipulated.

Suppose you have a set of entity relationships like this. One user has one password; A user belongs to a department, and a department has multiple users. A user can have multiple roles, and a role can have multiple users.

(1) @ OneToOne

The @onetoone is used to indicate a one-to-one relationship, placed on the dominant class. For example, if the user class has a primary key pwd_id that specifies the password table, placing @onetoone on the PWD field of the user class indicates that the user class and the password class are one-to-one and that the dominant class is the user class.

@OneToOne
@JoinColumn(name = "pwd_id")
private Password pwd;
Copy the code

Hibernate automatically generates associated columns in the user table. By default, the fields are named “subordinate class name _ subordinate primary key”, for example, password_id.

Sometimes you see the annotation @primaryKeyJoinColumn (name = “…” @id and @joinColumn (name = “…”) ).

(2) the @onetomany

When you analyze the relationship between users and departments, you can find that a user can belong to only one department, and a department can contain multiple users. So if you look at it from the department’s point of view

In the analysis of the relationship between users and departments, an employee can only belong to one Department, but a Department can contain multiple employees. From the perspective of departments, the relationship between departments and employees is one-to-many. Add the following annotation to the Department entity class Department:

1.	@OneToMany
2.	@JoinColumn(name = "department_id")
3.	private List<User> user;

Copy the code

If you do not specify @JoinColumn, Hibernate automatically generates a middle table to bind users and departments. The default name of the middle table is entity class table name _ attribute name specified in the entity class. For example, if the department table name is T_department and the user set attribute associated with the department entity class is user, the default generated intermediate table name is T_department_user. In practice, we recommend using the @JoinTable annotation to specify the intermediate table directly:

@OneToMany
@JoinTable(name = " t_department_user ", joinColumns = {
@JoinColumn(name = "department_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") })
private List<User> users;

Copy the code

The name attribute in @JoinColumn specifies the associated ID of the table corresponding to the current entity class (department). The inverseJoinColumns attribute specifies the association ID of the associated entity class table (employee) with the @JoinColumn annotation.

(3) @manytoone (many-to-one)

If we look at the relationship between users and departments from the perspective of users, it becomes many-to-one (multiple users belong to one department). Add the following annotation to the User entity class User:

@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
Copy the code

(4) @manytomany (many-to-many)

The relationship between users and roles is many-to-many, because a user can have multiple roles, and a role can belong to multiple employees. Many-to-many relationships are associated by creating an intermediate table, using the @JoinTable annotation.

Add the following annotation to the user entity class:

@ManyToMany
@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = {
@JoinColumn(name = "role_id") })
private List<Role> roles;
Copy the code

Add the following annotation to the role entity class:

@ManyToMany
@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "role_id") }, inverseJoinColumns = {
@JoinColumn(name = "user_id") })
private List<User> users;
Copy the code