前言
spring-data
项目中,为数据访问提供熟悉且一致的基于 Spring 的编程模型,同时仍保留底层数据存储的特殊特性,其中 spring-data-jpa
更容易实践领域驱动设计的特性,尤其收开发者欢迎。
然而,面对一些比较复杂的连表查询,如果严格按照 CQRS 的方案实践,方案又会显得比较笨重。在这个背景下, jpa 与 Mybatis 的混合方案,分别发挥了 jpa 模型的长处 与 Mybatis 动态 SQL 的长处,而规避了 jpa
动态 SQL 的短处与 Mybatis 模型的短处,受到了广泛的一致认可。
方案特点表现如下:
- Jpa 做模型的持久操作,以及单表查询。
- Mybatis 只做视图的复杂查询,并且不参与业务逻辑的运算(即代替 CQRS 查询层的逻辑)。
Mybatis PageHelper 的实践
在 spring-data
的中,提供了分页排序的 API 基本都是如下形状:
1 2
| Iterable<T> findAll(Predicate predicate, Sort sort); Page<T> findAll(Predicate predicate, Pageable pageable);
|
为了让 Mybatis 提供与 spring-data
一致的 API,我们希望使用如下:
1 2 3 4 5 6
| @Transactional(readOnly = true) public Page<OrderQueryMapper.OrderView>findAll(OrderQueryMapper.OrderParam orderParam, Pageable pageable){ return orderQueryMapper.findAll(orderParam, pageable); }
|
于是,我们的 Mapper 查询层利用 page-helper 做了如下设计:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Mapper public interface OrderQueryMapper { List<OrderView> findAll(OrderParam orderParam); default List<OrderView> findAll(OrderParam param, Sort sort) { return QueryHelper.sort(this::findAll, param, sort); }
default Page<OrderView> findAll(OrderParam param, Pageable pageable) { return QueryHelper.page(this::findAll, param, pageable); }
@Data class OrderParam { private String orderId; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public abstract class QueryHelper {
public static <RESULT, PARAM> Page<RESULT> page(Function<PARAM, List<RESULT>> mapperMethod, PARAM param, Pageable pageable) { String orderBy = Optional.of(pageable.getSort()) .map(Iterable::spliterator) .map(i -> StreamSupport.stream(i, false)) .orElseGet(Stream::empty) .map(a -> a.getProperty() + " " + a.getDirection().name()) .collect(Collectors.joining(",")); PageHelper.startPage(pageable.getPageNumber() + 1, pageable.getPageSize(), orderBy); try { com.github.pagehelper.Page<RESULT> result = (com.github.pagehelper.Page<RESULT>) mapperMethod.apply(param); return new PageImpl<>(result.getResult(), pageable, result.getTotal()); } finally { PageHelper.clearPage(); } }
public static <RESULT, PARAM> List<RESULT> sort(Function<PARAM, List<RESULT>> mapperMethod, PARAM param, Sort sort) { String orderBy = Optional.ofNullable(sort) .map(Iterable::spliterator) .map(i -> StreamSupport.stream(i, false)) .orElseGet(Stream::empty) .map(a -> a.getProperty() + " " + a.getDirection().name()) .collect(Collectors.joining(",")); PageHelper.orderBy(orderBy); try { return mapperMethod.apply(param); } finally { PageHelper.clearPage(); } } }
|