本系列目录:java
读取操做必须是无害的,暂时不考虑大并发把服务器压垮这种极端场景,就通常而言,咱们能够说,一个合格的查询接口所达到的效果应该是: 不管你执行多少次查询,系统的数据都是不会发生变化的spring
因此,对于一个陌生的系统,若是对方给了你【增删改查】四个接口,那么再没有深刻了解业务的状况下,你首先进行测试的接口,必定是查询接口数据库
为了达到一个合格的查询接口,对于系统的开发者的来讲,必须保证全部的查询业务接口里,不能有任何对业务实体的修改操做,换句话说,全部的查询操做,只是对系统瞬时的一个快照,不对数据产生修改,天然对整个系统的业务运转也不产生任何变更。安全
咱们常说的读写分离,那是在应对性能问题时的一种解决方案。而咱们这里特地换成了读写隔离,就是为了区分开二者。而这个隔离,是从更高层面来设计整个架构规范,是在项目设计刚开始的时候就考虑进去的。并且,实现难度小。服务器
即便是基于现有的代码作重构,也只要挪代码块就好了,也没有什么业务风险,这个咱们以后会再提到。架构
那么,很天然的,经过@Transactional(readOnly = true)
的控制,能够很是好的达到这个目的,这样,即便有开发人员不当心在其中作了修改操做,也会执行报错,给予很好的安全提示,这时,咱们就须要从新审视这个需求,是否须要将修改操做分离出来。并发
import org.springframework.stereotype.Service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; /** * 以订单为主体的查询业务处理类 */ @Service @Transactional(readOnly = true) public class OrderFinder { @Autowired OrderRepository orderRepository; @Autowired UserRepository userRepository; /** 批量查询订单 */ List queryOrderByIds(List<Long> orderIds) /** 运营控制台订单分页查询 */ List pagingOrdersOnConsole(int pageSize,int pageNumber) /** APP端用户订单分页查询 */ List pagingOrdersOnApp(Long userId,int pageSize,int pageNumber) // more methods and fields .. }
·app
有一些问题直得探讨:性能
Finder就等同于将Repository里的查询方法挪过来吗?测试
并非,首先,Finder
是一个查询业务的处理类。一个查询业务,意味着从调用端发起请求到结果返回,本次过程是进行一次完整的查询操做,更直观的来讲,像是下面这样
//..在一个入口层中,好比SpringMVC中的@Controller @Autowired private OrderFinder orderFinder; @GetMapping("/paging/") public CustomPagingResponse pagingOrders(int pageSize,int pageNumber){ return orderFinder.paging(pageSize,pageNumber); }
而并不是另一种为了删改某一个实体而经过主键或其余特定查询SQL来作出的查询操做,这种操做,将会在一个命令业务中直接经过Repository去作,好比
//..假定是在订单删除业务OrderDeleteService中的一部分 public void deleteOrder(Long orderId){ //根据条件定位到须要进行操做的Entity,这个过程,是命令操做的一部分,因此,它不是一个完整的查询业务,这个时候,不会用到Finder Order order = orderRepository.getById(orderId); //...接下来对order进行操做,省略 }
并且,每每在一个较为复杂的查询业务中,不只仅须要从数据库中获取数据,每每可能还须要经过各种协议的远程接口获取数据,进行整合,这就更加须要Finder来进行概括处理了。
·
每一个实体(Entity)类都须要有一个Finder吗?
并不必定,由于并非每一个实体都会有这种业务需求。好比咱们很容易想到,对于订单,会有不少终端须要经过各种条件查询订单列表,也会有某一条订单的详细信息。但相比之下,订单变动记录,可能惟一会被查询到的地方只会是在订单详情中的一个小列表,那么,实现的写法更倾向于以下这种:
public void OrderFinder{ @Autowired private OrderTrackRepository orderTrackRepository; //它依旧出如今 OrderFinder 中 public OrderDetailView queryOrderDetail(Long orderId){ //首先查询order基础数据 //而后补充查询订单变动数据 List<OrderTrack> orderTracks = orderTrackRepository.getByOrderId(orderId) //而后整合,返回整个View } }
因此,因为它只会存在于订单View中的一部分,天然不须要单独一个OrderDetailFinder
。固然若是将来OrderDetail
的代码量陡增,那是能够考虑重构的。
其实你们回看本身现有的项目,里面有不少诸如【报表】,【采购单】,【详细信息】等等,其实,都是系统某一个侧面的快照而已。
将这些东西都一一隔离出来,这个时候,再去审视整个系统,你会有一种云开雾散,柳暗花明又一村的感受。
由于剩下的命令操做,就是整个系统的脉动了。
详细参看以后的章节~