Section 15: SpringBoot uses JPA to access the database

JPA is the abbreviation of Java Persistence API and an ORM specification officially proposed!

JPA specifications are all in the package path: javax persistence.* For example, @ Entity, @ Id and @ Transient are all in this path. These are also some conventional annotations of ORM commonly used in the market.

Spring Data JPA is a JPA framework developed by spring based on Hibernate. It can greatly simplify the writing method of JPA, and realize the access and operation of data almost without writing specific code. In addition to CRUD, it also includes some common functions such as paging and sorting.

pom. Adding dependencies to XML

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>

application.properties configuration

spring.datasource.url=jdbc:mysql://localhost:3306/rumenz_springboot
spring.datasource.username=root
spring.datasource.password=root1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:/ddl/user-book.sql
spring.sql.init.data-locations=classpath:/ddl/user-book-data.sql

spring. jpa. hibernate. Whether DDL auto updates the database according to the entity class has four attribute values

Attribute value

effect

create

Every time you load hibernate, you will delete the last generated table, and then regenerate the new table according to your model class. Even if there is no change twice, you should do so. This is an important reason for the loss of database table data.

create-drop

Each time hibernate is loaded, the table is generated according to the model class, but the table is automatically deleted as soon as sessionFactory is closed.

update

The most commonly used attribute. When hibernate is loaded for the first time, the table structure will be automatically established according to the model class (provided that the database is established first). When hibernate is loaded later, the table structure will be automatically updated according to the model class. Even if the table structure is changed, the rows in the table still exist and the previous rows will not be deleted. It should be noted that when deployed to the server, the table structure will not be established immediately. It will not be established until the application runs for the first time.

validate

Every time hibernate is loaded, verify that the database table structure is created. It will only be compared with the tables in the database. No new table will be created, but new values will be inserted.

spring. sql. init. Whether mode uses SQL file to initialize the database has three values

Attribute value

effect

ALWAYS

Always initialize the database.

EMBEDDED

Initialize only the embedded database.

NEVER

Never initialize the database.

  • spring. sql. init. Schema locations specifies the SQL file for creating tables
  • spring. sql. init. Data locations specifies the data SQL file

Create entity class

User.java
@Getter
@Setter
@Builder
@AllArgsConstructor
@Entity //jpa required
@DynamicInsert //Fill default
@DynamicUpdate //Fill default
@Table(name = "user") //jpa required
@NoArgsConstructor
public class User {
    @Id //jpa required
    @GeneratedValue(strategy = GenerationType.IDENTITY) //jpa required
    private Integer id;
    private String name;
    private String domain;
    @Column(name = "age",columnDefinition = "tinyint default 0")
    private Integer age;
}

@GeneratedValue(strategy = GenerationType.IDENTITY) has the following types

  • TABLE: use a specific database TABLE to save the primary key.
  • SEQUENCE: generate the primary key according to the SEQUENCE of the underlying database, provided that the database supports the SEQUENCE.
  • IDENTITY: the primary key is automatically generated by the database (mainly automatic growth type)
  • AUTO: the primary key is controlled by the program.

Create a repository

The data persistence layer is responsible for accessing the database. The methods declared here generally do not need to be implemented. SQL statements can be automatically generated as long as they comply with the specifications of Jpa.

package com.rumenz.lession15.controller.repository;

import com.rumenz.lession15.controller.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

/**
 * @className: UserRepository
 * @description: TODO Class description
 * @author: Entry station rumenz com
 * @date: 2021/12/14
 **/

@Repository
public interface UserRepository extends PagingAndSortingRepository<User,Integer> {


    Optional<User> findById(Integer id);
    List<User> findDistinctUserByName(String name);
    Integer countUserByName(String name);
    List<User> readDistinctByName(String name);

    Page<User> findAllByName(String name, Pageable pageable);
}

Jpa can generate corresponding sql statements through the interface name, such as find By,read... By,query... By,count... By, And get By . These methods can include other expressions, such as setting the Distinct flag on the query to be created. The first by is used as a separator to indicate the beginning of the condition. Then, various conditions of entity attributes are defined And connected with And Or. For example:

interface RumenzRepository extends JpaRepository<Rumenz, Long> {

  List<Rumenz> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enable the distinct flag for queries
  List<Rumenz> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Rumenz> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  // Enable ignore case for individual attributes
  List<Rumenz> findByLastnameIgnoreCase(String lastname);
  // Enable ignore case for all attributes
  List<Rumenz> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // Enable static Order by for queries
  List<Rumenz> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Rumenz> findByLastnameOrderByFirstnameDesc(String lastname);
}

Give some examples

keyword

Method example

JPQL snippet

And

findByLastnameAndFirstname

... where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

... where x.lastname = ?1 or x.firstname = ?2

Is, Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

... where x.firstname = ?1

Between

findByStartDateBetween

... where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

... where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

... where x.age <= ?1

GreaterThan

findByAgeGreaterThan

... where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

... where x.age >= ?1

After

findByStartDateAfter

... where x.startDate > ?1

Before

findByStartDateBefore

... where x.startDate < ?1

IsNull, Null

findByAge(Is)Null

... where x.age is null

IsNotNull, NotNull

findByAge(Is)NotNull

... where x.age not null

Like

findByFirstnameLike

... where x.firstname like ?1

NotLike

findByFirstnameNotLike

... where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

... where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

... where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

... where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

... where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

... where x.lastname <> ?1

In

findByAgeIn(Collection ages)

... where x.age in ?1

NotIn

findByAgeNotIn(Collection ages)

... where x.age not in ?1

True

findByActiveTrue()

... where x.active = true

False

findByActiveFalse()

... where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

... where UPPER(x.firstame) = UPPER(?1)

There are three types of repositories

JpaRepository inherits pagingandsortingreposition, and pagingandsortingreposition inherits CrudRepository.

  • CrudRepository provides CRUD functions
  • Pagingandsorting repository provides paging and sorting capabilities
  • JPA repository provides JPA related methods, such as refreshing persistent data, batch deletion, etc.

service

The business logic layer is responsible for calling the Repository to process data and complete the business.

package com.rumenz.lession15.controller.service;

import com.rumenz.lession15.controller.entity.User;
import org.springframework.data.domain.Page;

import java.util.List;

/**
 * @className: UserService
 * @description: TODO Class description
 * @author: Entry station rumenz com
 * @date: 2021/12/14
 **/
public interface UserService {
    Integer save(User user);

    User get(Integer id);

    List<User> listByName(String name);

    Integer countByName(String name);

    List<User> readDistinctByName(String name);

    Page<User> listByNamePage(String name, Integer page, Integer pageSize);
}


//Implementation class


package com.rumenz.lession15.controller.service.lmpl;

import com.rumenz.lession15.controller.entity.User;

import com.rumenz.lession15.controller.repository.UserRepository;
import com.rumenz.lession15.controller.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * @className: UserServiceImpl
 * @description: TODO Class description
 * @author: Entry station rumenz com
 * @date: 2021/12/14
 **/
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserRepository userRepository;


    @Override
    public Integer save(User user) {
        User save = userRepository.save(user);
        return save.getId();
    }

    @Override
    public User get(Integer id) {
        Optional<User> opt = userRepository.findById(id);

        return opt.isPresent()?opt.get():null;
    }

    @Override
    public List<User> listByName(String name) {
        List<User> res = userRepository.findDistinctUserByName(name);
        return res;
    }

    @Override
    public Integer countByName(String name) {
        return userRepository.countUserByName(name);
    }

    @Override
    public List<User> readDistinctByName(String name) {

        return userRepository.readDistinctByName(name);
    }

    @Override
    public Page<User> listByNamePage(String name, Integer page, Integer pageSize) {

        Sort sort = Sort.by("id").descending();
        Pageable pageable= PageRequest.of(page-1, pageSize, sort);
        Page<User> res = userRepository.findAllByName(name, pageable);
        return res;
    }
}

Controller

The front-end controller is responsible for receiving the front-end request, calling service and returning data.

package com.rumenz.lession15.controller;

import com.rumenz.lession15.controller.entity.User;
import com.rumenz.lession15.controller.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @className: RumenzController
 * @description: TODO Class description
 * @author: Entry station rumenz com
 * @date: 2021/12/14
 **/
@RestController
@RequestMapping("/rumenz")
public class RumenzController {

    @Autowired
    UserService userService;

    //Save data
    //If the data with id=1 does not exist, add it
    //If the data with id=1 exists, it will be updated
    @RequestMapping("/save")
    public String save(){
        User user=User.builder().id(1).name("Entry station 123").domain("https://rumenz.com").build();
        Integer save = userService.save(user);
        return save.toString();
    }
    //Query data by id
    @GetMapping("/get")
    public User get(@RequestParam("id") Integer id){
        return userService.get(id);
    }


    //Band query condition
    @GetMapping("/listByName")
    public List<User> get(@RequestParam("name") String name){
        return userService.listByName(name);
    }

    //Query qualified quantity by criteria
    @GetMapping("/countByName")
    public Integer countByName(@RequestParam("name") String name){
        return userService.countByName(name);
    }

    //Band query condition
    @GetMapping("/readDistinctByName")
    public List<User> readDistinctByName(@RequestParam("name") String name){
        return userService.readDistinctByName(name);
    }

    //Paging query
    //Band query condition
    @GetMapping("/listByNamePage")
    public Page<User> listByNamePage(@RequestParam("name") String name, @RequestParam("page") Integer page, @RequestParam("pageSize") Integer pageSize){
        return userService.listByNamePage(name,page,pageSize);
    }

}

Source code address of this summary:

Added by asterinex on Wed, 23 Feb 2022 11:42:50 +0200