日期:2023-02-06 Author:Roobin

SpringDataJpa框架使用文档

一、什么是 Jpa ?

jpa 的全称是 Java Persistence API , 中文的字面意思就是 java 的持久层 API , jpa 就是定义了一系列标准,让实体类和数据库中的表建立一个对应的关系,当我们在使用 java 操作实体类的时候能达到操作数据库中表的效果(不用写sql ,就可以达到效果),jpa 的实现思想即是 ORM (Object Relation Mapping),对象关系映射,用于在关系型数据库和业务实体对象之间作一个映射。

jpa 并不是一个框架,是一类框架的总称,持久层框架 Hibernate 是 jpa 的一个具体实现,本文要谈的 spring data jpa 又是在 Hibernate 的基础之上的封装实现。

使用 jpa 是可以解决一些我们写 sql 语句的烦恼,相反另一个数据库层的框架 mybatis是专注 sql 语句的;

二、SpringDataJpa常用的 jpa 的配置

项目依赖

org.springframework.boot

spring-boot-starter-data-jpa

application.properties 配置

#项目端口的常用配置

server.port=8081

# 数据库连接的配置

spring.datasource.url=jdbc:mysql:///jpa?useSSL=false

spring.datasource.username=root

spring.datasource.password=zempty123

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#数据库连接池的配置,hikari 连接池的配置

spring.datasource.hikari.idle-timeout=30000

spring.datasource.hikari.connection-timeout=10000

spring.datasource.hikari.maximum-pool-size=15

spring.datasource.hikari.minimum-idle=5

spring.datasource.hikari.auto-commit=true

#通过 jpa 自动生成数据库中的表

spring.jpa.hibernate.ddl-auto=update

#该配置比较常用,当服务首次启动会在数据库中生成相应表,后续启动服务时如果实体类有增加属性会在数据中添加相应字段,

#原来数据仍在,该配置除了 update ,\

#还有其他配置值,

#create :该值慎用,每次重启项目的时候都会删除表结构,重新生成,原来数据会丢失不见。

#create-drop :慎用,当项目关闭,数据库中的表会被删掉。

#validate : 验证数据库和实体类的属性是否匹配,不匹配将会报错。

spring.jpa.show-sql=true

#该配置当在执行数据库操作的时候会在控制台打印 sql 语句,方便我们检查排错等。

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

#数据库的方言配置。

三、类映射到数据库表的常用注解

@Entity

用来注解该类是一个实体类用来进行和数据库中的表建立关联关系,首次启动项目的时候,默认会在数据中生成一个同实体类相同名字的表(table),也可以通过注解中的 name 属性来修改表(table)名称, 如@Entity(name=“stu”) , 这样数据库中表的名称则是 stu 。 该注解十分重要,如果没有该注解首次启动项目的时候你会发现数据库没有生成对应的表。

@Id

@Id 类的属性注解,该注解表明该属性字段是一个主键,该属性必须具备,不可缺少。

@GeneratedValue

该注解通常和 @Id 主键注解一起使用,用来定义主键的呈现形式,

该注解通常有多种使用策略:

@GeneratedValue(strategy= GenerationType.IDENTITY) 该注解由数据库自动生成,主键自增型,在 mysql 数据库中使用最频繁,oracle 不支持。

@GeneratedValue(strategy= GenerationType.AUTO) 主键由程序控制,默认的主键生成策略,oracle 默认是序列化的方式,mysql 默认是主键自增的方式。

@GeneratedValue(strategy= GenerationType.SEQUENCE) 根据底层数据库的序列来生成主键,条件是数据库支持序列,Oracle支持,Mysql不支持。

@GeneratedValue(strategy= GenerationType.TABLE) 使用一个特定的数据库表格来保存主键,较少使用。

以上的主键生成策略当中,在数据库 mysql 当中 IDENTITY 和 AUTO 用的较多,二者当中 IDENTITY 用的多些

@Column

是一个类的属性注解,该注解可以定义一个字段映射到数据库属性的具体特征,比如字段长度,映射到数据库时属性的具体名字等。

@Transient

是一个属性注解,该注解标注的字段不会被应射到数据库当中。

实例代码:

@Setter//lombok 的注解

@Getter//lombok 的注解

@Accessors(chain = true) //lombok 的注解

@Entity(name = "stu")

//@Table

public class Student {

@Id

@GeneratedValue(strategy= GenerationType.TABLE)

private long id;

@Column(length = 100)

private String name;

@Transient

private String test;

private int age;

private LocalTime onDuty;

private LocalDate onPosition;

private LocalDateTime birthdayTime;

}

四、使用SpringDataJpa进行增删改查

定义Dao层

定义一个 Student 的 dao 层,这样我们的增删改查就已经有了

public interface StudentRepository extends JpaRepository {

}

在 spring boot 项目中在 dao 层我们不需要写 @Repository 注解 ,我们在使用的时候直接注入使用就好,这里需要说明一点, 我们在更新数据的时候,可以先查询,然后更改属性,使用 save 方法保存就好。

使用关键字自定义查询

我们可以使用 jpa 提供的 find 和 get 关键字完成常规的查询操作,使用 delete 关键字完成删除,使用 count 关键字完成统计等

public interface StudentRepository extends JpaRepository {

// 查询数据库中指定名字的学生

List findByName(String name);

// 根据名字和年龄查询学生

List getByNameAndAge(String name, Integer age);

//删除指定名字的学生,删除时需要在Service层调用是添加事务注解@Transactional

Long deleteByName(String name);

// 统计指定名字学生的数量

Long countByName(String name);

}

jpa关键词查询是通过方法名称关键字的搭配,底层生成sql的方式来实现与数据库的交互,其关键词的搭配又很多方式,基本能覆盖表查询的所又情况,其余关键字查询可以自行百度;

使用 sql 增删改查

jpa同样支持写sql语句来操作数据,sql 有两种呈现形式:

JPQL 形式的 sql 语句,from 后面是以类名呈现的。

原生的 sql 语句,需要使用 nativeQuery = true 指定使用原生 sql

示例代码

public interface ClassRoomRepository extends JpaRepository {

//使用的 JPQL 的 sql 形式 from 后面是类名

// ?1 代表是的是方法中的第一个参数

@Query("select s from ClassRoom s where s.name =?1")

List findClassRoom1(String name);

//这是使用正常的 sql 语句去查询

// :name 是通过 @Param 注解去确定的

@Query(nativeQuery = true,value = "select * from class_room c where c.name =:name")

List findClassRoom2(@Param("name")String name);

}

sql 中的参数传递也有两种形式:

使用问号 ?,紧跟数字序列,数字序列从1 开始,如 ?1 接收第一个方法参数的值。

使用冒号:,紧跟参数名,参数名是通过@Param 注解来确定。

使用 Sort 来对数据进行一个排序

实例化Sort

public List getTeachers(String subject) {

// 第一种方法实例化出 Sort 类,根据年龄进行升序排列

Sort sort1 = Sort.by(Sort.Direction.ASC, "age");

//定义多个字段的排序

Sort sort2 = Sort.by(Sort.Direction.DESC, "id", "age");

// 通过实例化 Sort.Order 来排序多个字段

List orders = new ArrayList<>();

Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");

Sort.Order order2 = new Sort.Order(Sort.Direction.DESC, "age");

orders.add(order1);

orders.add(order2);

Sort sort3 = Sort.by(orders);

//可以传不同的 sort1,2,3 去测试效果

return teacherRepositoty.getTeachers(subject, sort1);

}

Dao层多传一个参数Sort

public interface TeacherRepositoty extends JpaRepository {

// 正常使用,只是多加了一个 sort 参数而已

@Query("select t from Teacher t where t.subject = ?1")

List getTeachers(String subject, Sort sort);

}

jpa 的分页操作

实例化 PageRequest (PageRequest是Pageable接口的实现类)

public Page getPage(@PathVariable("subject") String subject) {

// 第一种方法实例化 Pageable

Pageable pageable1 = PageRequest.of(1, 2);

//第二种实例化 Pageable

Sort sort = Sort.by(Sort.Direction.ASC, "age");

Pageable pageable2 = PageRequest.of(1, 2, sort);

//第三种实例化 Pageable

Pageable pageable3 = PageRequest.of(1, 2, Sort.Direction.DESC, "age");

//可以传入不同的 Pageable,测试效果

Page page = teacherRepositoty.getPage(subject, pageable3);

System.out.println(page.getTotalElements());

System.out.println(page.getTotalPages());

System.out.println(page.hasNext());

System.out.println(page.hasPrevious());

System.out.println(page.getNumberOfElements());

System.out.println(page.getSize());

return page;

}

PageRequest 一共有三个可以实例化的静态方法:

public static PageRequest of(int page, int size)

public static PageRequest of(int page, int size, Sort sort) 分页的同时还可以针对分页后的结果进行一个排序。

public static PageRequest of(int page, int size, Direction direction, String… properties) 直接针对字段进行排序。

Dao层多传一个参数Pageable

public interface TeacherRepositoty extends JpaRepository {

//正常使用,只是多加了一个 Pageable 参数而已

@Query("select t from Teacher t where t.subject = :subject")

Page getPage(@Param("subject") String subject, Pageable pageable);

}

五、jpa 使用 Specification

接口继承JpaSpecificationExecutor

public interface TeacherRepositoty extends JpaRepository , JpaSpecificationExecutor {

}

//JpaSpecificationExecutor提供了如下的几个方法供我们使用 方法参数:Specification

public interface JpaSpecificationExecutor {

Optional findOne(@Nullable Specification var1);

List findAll(@Nullable Specification var1);

Page findAll(@Nullable Specification var1, Pageable var2);

List findAll(@Nullable Specification var1, Sort var2);

long count(@Nullable Specification var1);

}

实例化 Specification

Specification 是一个函数式接口,里面有一个抽象的方法:

Predicate toPredicate(Root var1, CriteriaQuery var2, CriteriaBuilder var3);

参数说明:

Predicate 是用来建立 where 后的查寻条件的相当于上述sql语句的 age > 20。

Root 使用来定位具体的查询字段,比如 root.get(“age”) ,定位 age字段,

CriteriaBuilder是用来构建一个字段的范围,相当于 > ,= ,<,and …. 等等

CriteriaQuery 可以用来构建整个 sql 语句,可以指定sql 语句中的 select 后的查询字段,也可以拼接 where , groupby 和 having 等复杂语句。

代码示例

//多条件查询并排序

public List queryBanner(Integer location) {

return findAll(

//实例化 Specification 类

(root, query, criteriaBuilder) -> {

// 构建查询条件

Predicate predicate = criteriaBuilder.equal(root.get(“数据库字段”),与数据库字段比较的参数 );

// 使用 and 连接上一个条件

predicate = criteriaBuilder.and(

predicate,

criteriaBuilder.equal(root.get(数据库字段), 与数据库字段比较的参数));

return predicate;

},

//传入Sort排序参数进行排序

Sort.by(Sort.Order.desc("数据库字段")));

}

Jpa的Projection (投影映射)

作用:将从查询到的数据封装自定一的接口中;

自定义接口:

public interface TeacherProjection {

String getName();

Integer getAge();

@Value("#{target.name +' and age is' + target.age}")

String getTotal();

}

接口中的方法以 get 开头 + 属性名,属性名首字母大写, 例如 getName(), 也可以通过 @Value 注解中使用 target.属性名获取属性,也可以把多个属性值拼接成一个字符串。

定义好一个接口后,在查询方法中指定返回接口类型的数据即可;

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: