SpringDataJPA系列(4)Repository 中的方法返回值使用

SpringDataJPA系列(4)Repository 中的方法返回值使用

Repository 返回结构有哪些?

打开 SimpleJpaRepository 直接看它的 Structure 就可以知道,它实现的方法,以及父类接口的方法和返回类型包括:Optional、Iterable、List、Page、Long、Boolean、Entity 对象等,而实际上支持的返回类型还要多一些。

由于 Repository 里面支持 Iterable,所以其实 java 标准的 List、Set 都可以作为返回结果,并且也会支持其子类,Spring Data 里面定义了一个特殊的子类 Steamable,Streamable 可以替代 Iterable 或任何集合类型。

Steamable

这里单独介绍下Steamable,它是一个函数式接口,它继承了Iterable,所以使用它我们可以很方便的返回集合类型的数据。
在这里插入图片描述

官方给我们提供了自定义 Streamable 的方法,不过在实际工作中很少出现要自定义保证结果类的情况。其原理很简单,就是实现Streamable接口,自己定义自己的实现类即可

List/Stream/Page/Slice
  • List:根据条件纯列表式返回
  • Stream:通过使用 Java 8 Stream 作为返回类型来逐步处理查询方法的结果,要注意流的关闭
  • Page:带分页信息的返回,分页信息中包含:数据内容、分页数据、当前数据描述等信息。数据量大的时候避免使用,会隐含一次count(*)操作
  • Slice:只查询偏移量,不计算分页数据的返回,不关心总页数。这就是 Page 和 Slice 的主要区别,现代分页方式推荐这种方式的查询
Future /CompletableFuture 异步结果返回
@Async
Future<User> findByFirstname(String firstname); 
@Async
CompletableFuture<User> findOneByFirstname(String firstname); 
@Async
ListenableFuture<User> findOneByLastname(String lastname);

在实际工作中,直接在 Repository 这一层使用异步方法的场景不多,一般都是把异步注解放在 Service 的方法上面,这样的话,可以有一些额外逻辑,如发短信、发邮件、发消息等配合使用。使用异步的时候一定要配置线程池,这点切记,否则“死”得会很难看。万一失败我们会怎么处理?关于事务是怎么处理的呢?这种需要重点考虑的

Reactive 支持

其实Common里面提供的只是接口,而JPA里面没有做相关的Reactive 的实现,但是本身Spring Data Common里面对 Reactive 是支持的。如果我们引入spring-boot-starter-data-mongodb的依赖,会发现它天然地支持着 Reactive 这条线。这些内容会放在后续mongodb专题中讲解

返回结果小结

下表列出了 Spring Data JPA Query Method 机制支持的方法的返回值类型

在这里插入图片描述

DTO返回结果支持哪些

比较规范的开发团队中都会有这么一条规范:不能暴露底层数据结构,也就是不允许将实体entity直接返回给出去,所以就诞生出了VO/DTO/DO/PO等概念。

于是在开发中我们必须自己去写各种DO/DTO/VO之间转换,同时还产生了各种工具类:BeanUtil、Mapstruct、Dozer、Orika、ModelMapper、Jmapper等(比较推荐Mapstruct综合性能最佳)
Spring Data 正是考虑到了这一点,引入了Projections映射这一概念, 它指的是和 DB 的查询结果的字段映射关系。允许对专用返回类型进行建模,有选择地返回同一个实体的不同视图对象。
如果我们的User只需要返回name和email,那应该怎么做呢?

在这里插入图片描述

方法一:新建实体类和资源库

在这里插入图片描述

然后,新增一个 UserOnlyNameEmailEntityRepository,做单独的查询
在这里插入图片描述
很显然这种方法比较糟糕,当存在多种返回值的情况,我们难道要定义多个实体类和资源库吗?

当然这种方式也并非一无是处,对那些临时需求,奇葩需求,生命周期和演化方向不同需求,为了保证我们架构和代码的整洁性与业务可扩展性,我们这么做也不一种蛮不错的选择

方法二:定义DTO方式

在这里插入图片描述

然后定义单独的查询方法
在这里插入图片描述

下面是测试结果代码:

在这里插入图片描述
这里需要注意的是,如果我们去看源码的话,看关键的 PreferredConstructorDiscoverer 类时会发现,UserDTO 里面只能有一个全参数构造方法。

所以这种方式的优点就是返回的结果不需要是个实体对象,对 DB 不能进行除了查询之外的任何操作。

缺点就是因为DTO要实现转化必须要有set方法,一旦有 set 方法就可以改变里面的值,构造方法不能更改,必须全参数,这样如果是不熟悉 JPA 的新人操作的时候很容易引发 Bug。

方法三:POJO接口方式

这种方式与上面两种的区别是只需要定义接口,它的好处是只读,不需要添加构造方法,我们使用起来非常灵活,一般很难产生 Bug

在这里插入图片描述
仍然定义一个单独的查询方法:
在这里插入图片描述
下面是测试代码:
在这里插入图片描述
这个时候会发现我们的 userOnlyName 接口成了一个代理对象,里面通过 Map 的格式包含了我们的要返回字段的值(如:name、email)。

我们用的时候直接调用接口里面的方法即可,如 userOnlyName.getName() 即可;这种方式的优点是接口为只读,并且语义更清晰。(DTO/VO转换貌似有点不方便)

总结

如果不熟悉JPA各种返回值和特点,我们很难在实际项目中选择正确的使用方法。

越容易上手的技术其实越难以恰到好处的使用。就像Springboot出现后,许多不懂Spring的开发人员一旦遇到问题完全是只能百度和谷歌,如果搜不到,完全就处于懵逼状态,目前有太多的开发人员连二者的区别都弄不清楚。

JPA的使用看起来非常方便,如果没有进一步理解,很容易误用和乱用,从而导致性能和数据安全性方面的问题。使用SpringDataJPA非常简单,但是要用好SpringDataJPA我们还是需要花一些功夫的。

JPA(Java Persistence API)是Java平台用于持久化数据的规范,它允许开发者通过Java来管理关系型数据。在使用JPA时,通常会通过Repository接口来操作数据库,而Spring Data JPA为这个过程提供了便利,允许我们通过定义接口来实现数据访问层(DAO)的编写。 在Spring Data JPARepository,你可以使用Spring提供的查询方法命名规则来声明查询,也可以使用`@Query`注解直接编写原生的SQL语句或JPQL语句。如果你需要将查询结果直接映射到一个数据传输对象(DTO),而不是JPA实体类,你可以使用构造函数绑定的方式。 构造函数映射到DTO通常涉及以下几个步骤: 1. 定义一个DTO类,这个类通常不包含任何JPA注解。 2. 在Repository接口使用`@Query`注解编写SQL查询语句,并指定返回值类型为DTO类的实例。 3. 使用`@Query`注解的`nativeQuery`属性来指定是否为原生SQL查询。 4. 使用`ConstructorResult`和`ConstructorExpression`来指定构造函数参数,这些参数将与查询结果的列名相对应。 以下是一个简单的例子: ```java // DTO类 public class MyDto { private final String columnOne; private final Integer columnTwo; public MyDto(String columnOne, Integer columnTwo) { this.columnOne = columnOne; this.columnTwo = columnTwo; } // getters and setters } // Repository接口 public interface MyEntityRepository extends JpaRepository<MyEntity, Long> { @Query(value = "SELECT new MyDto(e.columnOne, e.columnTwo) FROM MyEntity e") List<MyDto> findCustomDto(); } ``` 在这个例子,`findCustomDto`方法使用`@Query`注解定义了一个查询,返回值是一个DTO对象列表。查询结果将通过`MyDto`的构造函数映射到DTO对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值