QueryWrapper的副作用

【IT老齐751】Service 与 DAO 层职责分离的实践之路_哔哩哔哩_bilibili

开发任务统一使用 @Select,禁止在Service中使用QueryWrappper进行业务构建

在现有的 Java开发中,绝大多数团队都遵循着MVC开发模式:

  • 视图部分(界面)发起请求
  • 请求发送给控制器
  • 控制器调用业务逻辑
  • 业务逻辑再向下调用数据持久层

耦合困境

MyBatis-Plus提供了一个 select 的方法,可以传入一个QueryWrapper包装器,能情况动态组织查询条件

查询条件组织好以后,select会将其转换为SQL语句来执行。这么做没问题。针对敏捷开发和快速的价值交付,这是非常好的实现

职责分离原则:

在 Service 这个层面上,Service 是承载业务逻辑的。从实现角度来说,业务逻辑表达的是业务调用的过程,重点是控制业务的流向和数据流

在实际落地过程中,Service 与具体技术耦合越少越好。就是在 Service 当中,我们可以调用某个方法,比如调用一个list方法,就可以获取所有信息的列表。

那这个list的方法是从mysql取还是从redis取,这个过程不应出现在Service类当中。严格意义上来说,这个list方法是应该被包含在DAO 层中进行封装。

未来在业务处理时,对于 list方法,如果今天是从msyql来查,就调用DAO的;如果换成了Redis,那么只需要在底层的DAO 层面上进行替换就行了

问题:QueryWrapper的构建逻辑被写在Service里:

虽然使用的是UserMapper的selectList来进行查询,但在构建查询条件时,是在Service中来构建的

同时在后面的age、name,这本质上是数据库的物理字段名

如果公司要进行微服务的改造建设,就把这些信息拆散了,采用了不同的数据库。尤其是采用 NoSQL进行数据处理时,mybatisplus不能用了

MyBatis-Plus:围绕 SQL 语法和关系型数据库的表结构(行、列、主键、外键)进行设计

使用@Select实现指责分离

如果未来底层实现逻辑发生变化,比如数据从mysql迁移到了oracle上,作为DAO层只需要进行相应调整,而上面的Service层,由于职责切割清晰,完全不需要做任何改动

lambdaQueryWrapper和lambdaQuery()演示

lambdaQueryWrapper

LambdaQueryWrapper,本质是类,最基础的用法:手动 new 一个 Wrapper 对象,然后传给 Mapper

List<User> users = userMapper.selectList(
    new LambdaQueryWrapper<User>()
        .eq(User::getAge, 25)
        .like(User::getName, "张")
);

lambdaQuery

lambdaQuery(),本质是IService 接口的默认方法,必须在 Service 层 (实现 IService 的类) 中使用,是 MyBatis-Plus 提供的“糖”,封装了 Wrapper 的创建过程,写代码更顺畅

底层仍基于 LambdaQueryWrapper,但提供了更流畅的链式 API

List<User> users = lambdaQuery()
    .eq(User::getAge, 25)
    .like(User::getName, "张")
    .list(); // 直接执行并返回结果

思考

看到了QueryWrapper的副作用,实际上以前用的多的是LambdaQueryWrapper,也是在Service层中使用,那样的话也会让Service层耦合DAO层的技术实现

lambdaQuery()也一样,虽然写的更流畅了,但同样有Service层耦合问题

更多推荐