一、前言

Spring Boot JPA 是 Spring 在 ORM 框架的基础上封装的一套 JPA 应用框架,具体的数据访问和操作实现还是依赖于 ORM 框架来完成,Spring Boot JPA 只是完成了接口操作的标准封装,包括增删改查等在内的常用功能,可以帮助开发者降低学习成本,同时极大的提升开发效率。

以 Spring Boot 的2.0版本为例,Spring Boot JPA 的底层依赖于 Hibernate 框架来完成数据库的访问和操作,如果你熟悉 Hibernate 的框架使用,那么可以轻松的上手并使用它。

二、项目实战

1.引入依赖

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

2.在application.properties增加相关配置

#数据库配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/my_db?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

其中spring.jpa.hibernate.ddl-auto参数是hibernate的一个配置属性,主要作用有:自动创建、更新、验证数据库表结构。

相关的可选参数如下:

  • create:每次加载 hibernate 相关实体表时会删除上一次生成的表,然后按照最新的 model 类生成新表,会造成数据库表数据丢失;
  • create-drop:每次加载 hibernate 时会根据 model 类生成新表,当服务关闭时,表自动删除,通常用于测试;
  • update:常用属性,第一次加载 hibernate 时会根据 model 类自动建表,以后加载 hibernate 时根据 model 类自动更新表结构,但是不会删除表中的数据;
  • validate:每次加载 hibernate 时会验证数据库表的结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值;

spring.jpa.show-sql参数用于打印出自动生成的 SQL,方便调试。

3.创建实体

package com.example.dataproject.entity;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;

/**
 * @author qx
 * @date 2024/8/7
 * @des 用户表
 */
@Entity
@Table(name = "t_user")
@Getter
@Setter
@ToString
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;

    private Integer age;

    private String phone;


}
  • @Entity注解用于标识User类是一个持久化的实体类;
  • @Table注解用于标识User类映射到数据库中的表名称;
  • @Id注解用于标识User映射到数据库的主键字段
  • @GeneratedValue注解用于标识User映射到数据库的主键为自增类型
  • @Column注解用于标识User映射到数据库的字段相关信息

4.创建数据访问接口

package com.example.dataproject.dao;

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

/**
 * @author qx
 * @date 2024/8/7
 * @des 数据持久层
 */
public interface UserDao extends JpaRepository<User, Long> {
}

5.单元测试

package com.example.dataproject;

import com.example.dataproject.dao.UserDao;
import com.example.dataproject.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class DataProjectApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void add() {
        //新增数据
        User user = new User();
        user.setName("admin");
        user.setAge(20);
        user.setPhone("18899998888");
        userDao.save(user);
    }

    @Test
    void query() {
        //查询数据
        List<User> userList = userDao.findAll();
        System.out.println(userList);
    }

    @Test
    void update() {
        //修改数据
        User user = userDao.findById(1L).orElse(null);
        if (user != null) {
            user.setAge(22);
            userDao.save(user);
        }
    }

    @Test
    void delete() {
        //删除数据
        userDao.deleteById(1L);
    }
}

我们启动程序先执行add方法,并查看数据表。

SpringBoot整合JPA实现数据表增删改查_数据库

测试query方法:

SpringBoot整合JPA实现数据表增删改查_JPA_02

测试update方法:

SpringBoot整合JPA实现数据表增删改查_JPA_03

测试delete方法:

SpringBoot整合JPA实现数据表增删改查_SpringBoot_04

三、使用进阶

1.简单查询

Spring Boot JPA 不仅为开发者封装了常用的模板方法,还支持根据方法名来动态生成 SQL 语句,比如findByXX,countByXX,getByXX后面跟属性名称,当调用方法的时候会自动生成响应的 SQL 语句,具体示例如下:

package com.example.dataproject.dao;

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

/**
 * @author qx
 * @date 2024/8/7
 * @des 数据持久层
 */
public interface UserDao extends JpaRepository<User, Long> {

    User findByPhone(String phone);

    Integer countByName(String name);

}

编写单元测试验证内容的正确性。

@Test
    public void queryTest(){
        User user = userDao.findByPhone("18899998888");
        System.out.println("user="+user);

        Integer count = userDao.countByName("admin");
        System.out.println("count="+count);
    }

执行查询:

SpringBoot整合JPA实现数据表增删改查_JPA_05

方法上支持 SQL 语句中的关键字,比如AndOrLikeOrderBy等。

具体关键字上的使用和生成的 SQL 对应的关系如下:

SpringBoot整合JPA实现数据表增删改查_数据库_06

2.复杂查询操作

在实际的开发过程中,由于业务的需要,我们经常需要编写复杂的 SQL 语句,比如链表查询,分页查询等,这个时候就需要用到自定义 SQL 语句的操作了。

其实大部分的 SQL 语句都可以通过方法来动态生成,如果想自定义 SQL 查询,Spring Boot JPA 也是支持的,操作上很简单。

在接口方法上,添加@Query注解,即可实现自定义 SQL 语句;如果涉及到新增、修改和删除操作,需要再加上@Modifying注解,同时也需要添加@Transactional注解事务支持。

具体示例如下:

package com.example.dataproject.dao;

import com.example.dataproject.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author qx
 * @date 2024/8/7
 * @des 数据持久层
 */
public interface UserDao extends JpaRepository<User, Long> {

    User findByPhone(String phone);

    Integer countByName(String name);


    @Query("select u from User u where u.phone=?1")
    User findByUserPhone(String phone);


    @Modifying
    @Transactional
    @Query("delete from User u where u.name=?1")
    int deleteByName(String name);
    

}

编写单元测试验证内容的正确性。

@Test
    void sqlTest() {
        User user = userDao.findByUserPhone("18899998888");
        System.out.println("user=" + user);
    }
 @Test
    void deleteTest() {
        userDao.deleteByName("admin");
    }

执行查询测试方法:

SpringBoot整合JPA实现数据表增删改查_数据库_07

执行删除测试方法:

SpringBoot整合JPA实现数据表增删改查_SpringBoot_08

SpringBoot整合JPA实现数据表增删改查_JPA_09

值得注意的是:这里自定义的 SQL 语句并非数据库中的 SQL 语句,而是 hibernate 所支持 SQL 语句,简称 hsql,例如表名要采用 Java 实体而非数据库中真实的表名,否则可能会报错。

3.分页查询

分页查询,在实际的业务开发中非常常见,其实 Spring Boot JPA 已经帮助开发者封装了分页查询的方法逻辑,在查询的时候传入Pageable参数即可。

当前的数据表存在两条数据:

SpringBoot整合JPA实现数据表增删改查_数据库_10

编写测试方法:

@Test
    void pageTest() {
        int page = 0, size = 10;
        Pageable pageable = PageRequest.of(page, size);

        Page<User> userPage = userDao.findAll(pageable);
        System.out.println("总页数:" + userPage.getTotalPages());
        System.out.println("总数量:" + userPage.getTotalElements());
        System.out.println("数据:" + userPage.getContent());
    }

执行测试方法:

SpringBoot整合JPA实现数据表增删改查_JPA_11

4.多表查询

多表查询,也是实际开发中经常会碰到的场景,Spring Boot JPA 提供了两种实现方式,第一种是利用 Hibernate 的级联查询来实现,第二种是自定义 SQL 语句来实现。

第一种就不多说了,主要通过@OneToOne@OneToMany@ManyToOne@ManyToMany@JoinTable注解来完成多表的级联查询,不过这种方式需要在数据库层面建立外键关联,通过外键来完成级联查询,不推荐采用。

下面我们来介绍一下自定义 SQL 语句来实现,实现起来也很简单,示例如下:

我们先创建一个实体类,关联用户ID

package com.example.dataproject.entity;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.math.BigDecimal;

/**
 * @author qx
 * @date 2024/9/3
 * @des
 */
@Entity
@Table(name = "t_order")
@Getter
@Setter
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long userId;

    private String goodsName;

    private BigDecimal totalPrice;


}

下面我们来介绍一下自定义 SQL 语句来实现,实现起来也很简单,示例如下:

package com.example.dataproject.dao;

import com.example.dataproject.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.Map;

/**
 * @author qx
 * @date 2024/9/3
 * @des
 */
public interface OrderDao extends JpaRepository<Order, Long> {

    @Query(nativeQuery = true, value = "select u.name,u.phone,o.* from t_order o INNER JOIN t_user u on u.id=o.user_id")
    List<Map<String, Object>> findCustomer();
}

编写单元测试,验证代码的正确性。

package com.example.dataproject;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.dataproject.dao.OrderDao;


import java.util.List;
import java.util.Map;

@SpringBootTest
class DataProjectApplicationTests {

    @Autowired
    private OrderDao orderDao;


    @Test
    void testLink(){
        List<Map<String, Object>> maps = orderDao.findCustomer();
        System.out.println(JSON.toJSONString(maps));
    }
}

输出结果如下:

SpringBoot整合JPA实现数据表增删改查_JPA_12

5.属性映射屏蔽操作

如果某个实体类中的属性,不想被映射到数据库,可以添加@Transient注解来实现,示例如下。

package com.example.dataproject.entity;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.math.BigDecimal;

/**
 * @author qx
 * @date 2024/9/3
 * @des
 */
@Entity
@Table(name = "t_order")
@Getter
@Setter
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long userId;

    private String goodsName;

    private BigDecimal totalPrice;

    @Transient
    private String desc;
}

SpringBoot整合JPA实现数据表增删改查_JPA_13