Spring Data JPA 使用

Java 持久层框架访问数据库的方式大致分为两种。一种以 SQL 中心,封装一定程度的 JDBC 操作,比如 MyBatis。另一种是以 Java Entity 为中心,将实体的关系对应到数据库表之间的关系,如 ORM (Object Relational Mapping) 工具。

JAP (Java Persistence API) 就是用来整合第三方 ORM 框架的,即建立一套标准的方式。通过注解或 XML 描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中

Spring Data JPA 介绍

什么是 Spring Data JPA

Spring 提供的一个用于简化 JPA 开发的框架。可以极大的简化 JPA 的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。

  • Spring Data JPA 是 Spring Data 中的一个子模块

  • JPA 是一套标准接口,而 Hibernate 是 JPA 的实现,而 Spring Data JPA 底层默认实现是使用Hibernate

  • Spring Data JPA 的首个接口就是 Repository,它是一个标记接口。只要我们的接口实现这个接口,那么我们就相当于在使用 Spring Data JPA 了。

  • 就是说,只要我们实现了这个接口,我们就可以使用“按照方法命名规则”来进行查询。

JPA、Hibernate 与 Spring Data JPA

JPA 是一套 ORM 规范——即只提供接口,显然接口不能直接拿来使用。Hibernate实现了 JPA 规范,在 Hibernate 中有自己的独立 ORM 操作数据库方式,也有 JPA 规范实现的操作数据库方式。

虽然 ORM 框架都实现了 JPA 规范,但是在不同 ORM 框架之间切换是需要编写的代码有一些差异,而通过使用 Spring Data Jpa 能够方便大家在不同的 ORM 框架中间进行切换而不要更改代码。并且 Spring Data Jpa 对 Repository 层封装的很好,可以省去不少的麻烦。

Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。

JPA 实体相关注解

@Entity

标注位置:实体类声明语句之前;

主要作用:标注该Java类为实体类,且将其映射到指定的数据库表。

@Table

标注位置:实体类声明语句之前,与@Entity注释并列使用;

主要作用:标注当前实体类映射到数据库中的数据表名,当实体类与数据表名不同时使用。

@Id

标注位置:实体类的属性声明语句之前,或属性的getter()方法之前;

主要作用:指定该实体类的当前属性映射到数据表的主键列。

@GeneratedValue

标注位置:与@Id注释配合使用;

主要作用:通过其strategy属性指定数据表主键的生成策略。默认情况下,JPA自动选择最适合底层数据库的主键生成策略,即SqlServer对应identity,而MySQL对应auto increment。

img

@Column

标注位置:实体类的属性声明语句之前,或属性的getter()方法之前;

主要作用:标注实体类的当前属性映射到数据库表的字段名,当属性名与数据表字段名不一致时使用。

img

@Transient

标注位置:实体类的属性声明语句之前,或属性的getter()方法之前;

主要作用:标注实体类的当前属性不进行数据表字段的映射,ORM框架将忽略此映射,如实体类的getInfo()方法通常不需要映射到数据表的字段上。

@Temporal

标注位置:实体类的属性声明语句之前,或属性的getter()方法之前;

主要作用:标注实体类中Date类型(Java核心API中未定义Date类型的精度)的属性映射到数据表字段的具体精度(数据库中Date类型的数据有DATE、TIME和TIMESTAMP三种精度)。

基本CRUD操作

Repository接口

仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别。

CRUDRespository接口

继承Repository,实现了一组CRUD相关的方法。

img

命名参数,索引参数

  • 索引参数如下所示,索引值从1开始,查询中 ”?X” 个数需要与方法定义的参数个数相一致,并且顺序也要一致

@Modifying

@Query(“update User u set u.firstname = ?1 where u.lastname = ?2”)

int setFixedFirstnameFor(String firstname, String lastname);

  • 命名参数(推荐使用这种方式)
    可以定义好参数名,赋值时采用@Param(“参数名”),而不用管顺序。如下所示:

public interface UserRepository extends JpaRepository<User, Long> {

@Query(“select u from User u where u.firstname = :firstname or u.lastname = :lastname”)

User findByLastnameOrFirstname(@Param(“lastname”) String lastname,

​ @Param(“firstname”) String firstname);

}

PagingAndSortRespository接口查询

该接口继承了CrudRepository接口,提供了两个方法,实现了分页和排序的功能了

img

JpaRepository接口

该接口继承了PagingAndSortingRepository接口。同时也继承QueryByExampleExecutor接口,这是个用“实例”进行查询的接口

img

事务在spring data jpa中的使用,@Modifying @Transactional的综合使用

@Modifying表示是更新执行

@Transactional带事务

JpaSpecificationExecutor接口

该接口提供了对JPA Criteria查询(动态查询)的支持。

spring data jpa 通过创建方法名来做查询,只能做简单的查询,那如果我们要做复杂一些的查询呢,多条件分页怎么办,这里,spring data jpa为我们提供了JpaSpecificationExecutor接口,只要简单实现toPredicate方法就可以实现复杂的查询

1.首先让我们的接口继承于JpaSpecificationExecutor

2.JpaSpecificationExecutor提供了以下接口

img

其中Specification就是需要我们传进去的参数,它是一个接口

img