写点什么

强强联手!腾讯 T6 大佬带你玩转 SpringData,GitHub 上线分享秒过万

发布于: 2021 年 06 月 02 日
强强联手!腾讯T6大佬带你玩转SpringData,GitHub上线分享秒过万

今日分享开始啦,请大家多多指教~

1. 什么是 SpringData

Spring Data :Spring 的一子项目。用于简化数据库访问,支持 NoSQL 和关系数据存储。其主要目标是使数据库的访问变得方便快捷。

SpringData 项目所支持 NoSQL 存储:

  • MongoDB (文档数据库)

  • Neo4j(图形数据库)

  • Redis(键/值存储)

  • Hbase(列族数据库)

SpringData 项目所支持的关系数据存储技术:

  • JDBC

  • JPA

Spring Data JPA : 致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就只是声明持久层的接口(有点类似于 mybatis 采用接口代理方式),其他都交给 Spring Data JPA 来帮你完成!

框架怎么可能代替开发者实现业务逻辑呢?比如:当有一个 UserDao.findUserById() 这样一个方法声明,大致应该能判断出这是根据给定条件的 ID 查询出满足条件的 User 对象。Spring Data JPA 做的便是规范方法的名字,根据符合规范的名字来确定方法需要实现什么样的逻辑。

2、SpringData JPA 入门

2.1、SpringData 开发步骤

使用 Spring Data JPA 进行持久层开发需要的四个步骤:

  • 配置 Spring 整合 JPA

  • 在 Spring 配置文件中配置 Spring Data:

让 Spring 为声明的接口创建代理对象。配置了 jpa:repositories 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。

  • 声明持久层的接口,该接口继承 Repository:

Repository 是一个标记型接口,它不包含任何方法,如必要,Spring Data 可实现 Repository 其他子接口,其中定义了一些常用的增删改查,以及分页相关的方法。

  • 在接口中声明需要的方法:

Spring Data 将根据给定的策略(具体策略稍后讲解)来为其生成实现代码。

2.2、SpringData 环境搭建

创建 maven 项目:



2.3、入门案例

2.3.1、Lombok 插件

开发中我们要写大量的 java 实体类,虽然 idea 能够直接生成 get 和 set 方法,有的时候碰到那种属性很多的实体类,看代码都看的头痛。Lombok 插件,它能够让代码更简洁好看,不需要生成 get 和 set 方法,编译也能通过。更加直白地说,就是帮助我们快速生成 get 和 set 方法。

同时还需要在 pom 中引入

上面这些步骤做完之后,只要在书写的 pojo 上添加对应的注解即可:@Data 注解

这样在编写 pojo 的时候,只需要添加属性即可, 其他的 get 和 set 自动生成(在源码中是没有 get 和 set 的,只是在生成的 class 源码中存在)。

需要在数据库中创建 User 表

2.3.2、编写 pom 文件



2.3.3、编写 springboot 的配置文件

2.3.4、编写启动类

2.3.5、编写 Controller 类

2.3.6、编写 Service

接口的编写:

编写实现类:

2.3.7、编写 repository

public interface UserRepository extends JpaRepository<User,Integer> { }

关于 Spring Data JPA 的 Repository 接口后续会详细说明

2.3.8、完整的 pojo

2.3.9、测试结果

3、Repository 接口

Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法

@Indexed

public interface Repository<T, ID> { }

Spring Data 可以让我们自定义接口,只要遵循 Spring Data 的规范,就无需写实现类。

spring data 支持的关键字



4、Repository 子接口

基础的 Repository 提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系如下:

  • Repository: 仅仅是一个标识,表明任何继承它的均为仓库接口类

  • CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法

  • PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法

  • JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法

  • 自定义的 XxxxRepository 需要继承 JpaRepository,这样的 XxxxRepository 接口就具备了通用的数据访问控制层的能力。

  • JpaSpecificationExecutor: 不属于 Repository 体系,实现一组 JPA Criteria 查询相关的方法

5、使用 @Query 注解

5.1 使用数字占位符

可以在 Repository 方法中,将查询直接在相应的接口方法上(类似于 mybatis 的注解开发),结构更为清晰。

@Query("select u from User u where u.id = ?1")

public User findUserById(Integer id);

说明:

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

  2. 表名需要使用 POJO 代替,并且用别名。

  3. select 后面不能使用*,可以使用别名代替

5.2 使用参数占位符和注解

上面使用的数字占位符非常不友好,可以使用参数占位符代替,但是需要在方法上使用 @Param 注解声明参数占位符的名称,

@Query("select u from User u where u.username = :name")

public User findUserByName(@Param("name") String name);

@Param 注解中标注的参数名。

如果是 @Query 中有 LIKE 关键字,后面的参数需要前面或者后面加 %,这样在传递参数值的时候就可以不加 %:

  • @Query(“select o from UserModel o where o.name like ?1%”)

public List<UserModel> findByUuidOrAge(String name);

  • @Query(“select o from UserModel o where o.name like %?1”)

public List<UserModel> findByUuidOrAge(String name);

  • @Query(“select o from UserModel o where o.name like %?1%”)

public List<UserModel> findByUuidOrAge(String name);

  • 还可以使用 @Query 来指定本地查询,只要设置 nativeQuery 为 true,比如:

@Query(value="select * from tb_user where name like %?1" ,nativeQuery=true)

public List<UserModel> findByUuidOrAge(String name);

6、@Modifying 注解和事务

@Query 与 @Modifying 执行(CUD)操作这两个 annotation 一起声明,可定义个性化更新操作,例如只涉及某些字段更新时最为常用,示例如下:

注意:在调用的地方必须加事务,没有事务不能正常执行

对于自定义的方法,如需改变 SpringData 提供的事务默认方式,可以在方法上注解 @Transactional 声明。

7、CrudRepository 接口

CrudRepository 接口提供了最基本的对实体类的添删改查操作

8、PagingAndSortingRepository 接口

该接口提供了分页与排序功能

9、JpaRepository 接口

该接口提供了 JPA 的相关功能

10、JpaSpecificationExecutor 接口

不属于 Repository 体系,实现一组 JPA Criteria 查询相关的方法

Specification:封装 JPA Criteria 查询条件。通常使用匿名内部类的方式来创建该接口的对象

11、多表操作

11.1、一对一查询

一对一的业务场景:用户和地址,一个用户拥有唯一的户籍归属地



针对一对一的查询操作,需要在对应的一的 pojo 中添加另外一方的对象,并且使用

@OneToOne

@JoinColumn(name=“uid” , referencedColumnName =“id”)注解配置映射关系。name=“uid” 当前的外键列名,referencedColumnName =“id”,关联的对象的中的主键名称

在 pojo 中如果存在外键,需要删除或者忽略。而配置的 OneToOne 的注解就相当于外键列。

11.2、一对多查询

一对多业务场景假设:作者和作品,一个作者对应多个作品,每个作品对应唯一的一个作者。

11.2.1 Book 和 User 实体


针对一对多的操作:

在一的一方的 Pojo 中添加多的一方的引用:List 集合,同时需要在属性添加对应的注解

@OneToMany : 声明当前的属性是一个一对多的设置,SpringData JPA 会进行关联查询

@JoinColumn(name = “uid” ,referencedColumnName = “id”) 设置关联的外键和主键的关系

11.2.2 BookRepository

11.3、 多对多查询

11.3.1 表结构

多对多场景假设:订单和商品之间的关系,一个订单中存在多类商品,一类商品可以出现在多个订单中。



11.3.2 POJO 的编写


在多对多查询的时候,分为主表和副表(主查询对象和次查询对象)

针对上面的案例:

Order 是主查询对象,Item 是次查询对象,但在两个 POJO 中都需要使用集合表示多的这种关系。同时在上面添加 @ManyToMany 注解,表示多对多

在主查询 Order 中:

需要使用 @JoinTable 声明多对多的中间和字段映射关系

@JoinTable(name=“tb_orderdetail”,

joinColumns = { @JoinColumn(name=“order_id”,referencedColumnName = “id”)},

inverseJoinColumns = {@JoinColumn(name=“item_id”,referencedColumnName=“id”)})

@JoinTable 注解中的 name 书写中间表名

joinColumns 书写主查询的主键在中间表中的外键列名

referencedColumnName 书写主查询的主键列名(可以省略)

​ inverseJoinColumns 书写关联的次查询在中间表中的外检列名

次查询 Item 中:

需要在集合属性上的 @ManyToMany 注解中使用

​ targetEntity 属性编写主查询的类

​ mappedBy 属性编写主查询管理的次查询的属性名

千万别踩的坑:

在给主查询和次查询的 pojo 中添加 get 和 set 方法的时候,注意不要形成嵌套。

在次查询中的集合不要再生成 get 和 set 方法了,否则就会嵌套,无法正常进行数据的 json 操作。

今日份分享已结束,请大家多多包涵和指点!

用户头像

还未添加个人签名 2021.04.20 加入

Java工具与相关资料获取等WX: pfx950924(备注来源)

评论

发布
暂无评论
强强联手!腾讯T6大佬带你玩转SpringData,GitHub上线分享秒过万