Spring boot integrates Spring Data JPA

1. Introduction to JPA

JPA (Java Persistence API) is a Java Persistence API. It is a Java persistence specification based on ORM proposed by Sun company.

The full name of ORM (Object Relational Mapping) is Object Relational Mapping. The mainstream Java ORM frameworks include Mybatis, Hibernate, etc.

2. Spring Data JPA

Spring Data JPA is a module of Spring Data framework, which can simplify the implementation of JPA. In addition, Spring Data JPA can also help us simplify the development of persistence layer. For simple queries, Spring Data JPA can resolve according to the method name and automatically generate query statements for query; For complex queries, Spring Data JPA also supports native SQL.

3. Spring Data JPA practice

Create a SpringBoot project and use JPA to implement simple CRUD.

3.1 introducing dependencies

POM files are as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.2 configuring JPA and MySQL

application. The YML configuration file is as follows:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/jpa_test?serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update # When there is data in the table, it will not be cleared, only updated
    # Console display SQL
    show-sql: true 

3.3 writing entity classes

This article takes the User class as an example:

package com.example.entity;

import lombok.Data;

import javax.persistence.*;

/**
 * @Author join
 * @Date 2021/10/13
 */
@Data
@Entity
@Table(name = "user")
public class User extends BaseEntity{

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "name", columnDefinition = "varchar(20) not null")
    private String name;
}

The User class contains id and name attributes, and the User class also inherits BaseEntity. When there are multiple entity classes in the project, we might as well encapsulate the common fields in the data table in BaseEntity, such as create_time,update_time, etc.

package com.example.entity;

import lombok.Data;

import javax.persistence.*;
import java.util.Date;

/**
 * @Author join
 * @Date 2021/10/13
 */
@Data
@MappedSuperclass
public class BaseEntity {

    @Column(name = "create_time")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createTime;

    @Column(name = "update_time")
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;

    @PrePersist
    public void prePersist() {
        Date now = new Date();
        if (createTime == null) {
            createTime = now;
        }
        if (updateTime == null) {
            updateTime = now;
        }
    }

    @PreUpdate
    public void preUpdate() {
        updateTime = new Date();
    }

    @PreRemove
    public void preRemove() {
        updateTime = new Date();
    }
}

Note explanation:

  • @Data: lombok annotation, which can automatically generate methods such as get(), set(), toString();
  • @Entity: JPA annotation, which declares that this class is an entity class and must be used with @ Id;
  • @Table: JPA annotation, indicating that the entity class will be mapped to the user table of the database (name specifies the table name);
  • @Id: JPA annotation, declaring the primary key;
  • @GeneratedValue: JPA annotation, which indicates the generation strategy of the primary key, and IDENTITY indicates the use of self incrementing id;
  • @Column: JPA annotation, which declares which field the attribute of the entity object is mapped to in the data table. Name specifies the field name and columnDefinition specifies the field definition.
  • @MappedSuperclass: JPA annotation, which is applied to the parent class of the entity class. The class under the annotation will not be mapped to the data table, but its properties will be mapped to the data table of the child class.
  • @PrePersist: the method modified by @ PrePersist is called before persisting the entity to the database;
  • @PreUpdate: the method modified by @ PreUpdate is called when an attribute of the entity changes, such as updating the update of the entity_ time;
  • @PreRemove: the method modified by @ PreRemove is called before the entity is deleted from the database.

3.4 definition of repository

Write UserRepository:

package com.example.repository;

import com.example.entity.User;
import lombok.NonNull;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

/**
 * @Author join
 * @Date 2021/10/13
 */
public interface UserRepository extends JpaRepository<User, Integer> {

    @NonNull
    Optional<User> findByName(@NonNull String name);
}

The rud repository() method can be automatically inherited from the rud repository() method, such as save repository(). In the above code, we also customized a method findByName(), and JpaRepository can automatically implement the corresponding logic according to the method name.

Be aware of the naming conventions of the JpaRepository.

3.5 define controller

Write UserController:

package com.example.controller;

import com.example.entity.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

/**
 * @Author join
 * @Date 2021/10/13
 */
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @RequestMapping(path = "addUser", method = RequestMethod.POST)
    @ResponseBody
    public void addUser(@RequestBody User user) {
        userRepository.save(user);
    }

    @RequestMapping(path = "deleteUser", method = RequestMethod.POST)
    @ResponseBody
    public void deleteUser(@RequestBody User user) {
        userRepository.delete(user);
    }

    @RequestMapping(path = "/getById/{id}", method = RequestMethod.GET)
    @ResponseBody
    public User queryUserById(@PathVariable("id") int id) {
        return userRepository.findById(id).orElse(null);
    }

    @RequestMapping(path = "/getByName/{name}", method = RequestMethod.GET)
    @ResponseBody
    public User queryUserByName(@PathVariable("name") String name) {
        Optional<User> optional = userRepository.findByName(name);
        return optional.orElse(null);
    }
}

In the above code, we have implemented four methods, which are used to create, delete and query users respectively.

3.6 testing

Start the project and use Navicat to view 'JPA'_ From the data table under 'test' library, we found that JPA automatically created the user table for us:


The table contains the id and name defined in the User class and the create defined in the BaseEntity class_ time,update_time and other fields.

Add user

Use Postman to send a post request and add user:


Query user

Query with id:


Query with name:

4. JPA analysis principle

JPA follows the principle of Convention over configuration and the naming rules defined by spring and JPQL. Spring provides a mechanism for query construction according to naming rules. This mechanism will filter out some keywords from the method name, such as find... By, read... By, query... By, count... By and get... By. The system will parse the method name into two sub statements according to the keyword. The first by is the keyword that distinguishes the two sub statements. The clause before by is a query clause, indicating the returned object. The rest is the conditional clause. If the method name is findBy..., then the object specified when repository is defined will be returned. The following table shows the usage instructions of some keywords:

Keyword
Sample
JPQL snippet
AndfindByLastnameAndFirstname... where x.lastname = ?1 and
OrfindByLastnameOrFirstname... where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals... where x.firstname = ?1
BetweenfindByStartDateBetween... where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan... where x.age < ?1
LessThanEqualfindByAgeLessThanEqual... where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan... where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual... where x.age >= ?1
AfterfindByStartDateAfter... where x.startDate > ?1
BeforefindByStartDateBefore... where x.startDate < ?1
IsNullfindByAgeIsNull... where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull... where x.age not null
LikefindByFirstnameLike... where x.firstname like ?1
NotLikefindByFirstnameNotLike... where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith... where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith... where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining... where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc... where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot... where x.lastname <> ?1
InfindByAgeIn(Collection ages)... where x.age in ?1
NotInfindByAgeNotIn(Collection age)... where x.age not in ?1
TRUEfindByActiveTrue()... where x.active = true
FALSEfindByActiveFalse()... where x.active = false
IgnoreCasefindByFirstnameIgnoreCase... where UPPER(x.firstame) = UPPER(?1)

Welcome criticism and correction!!!

Tags: Java Back-end Database Spring Boot

Posted by loopykd on Sat, 16 Apr 2022 17:32:58 +0930