关于mybatis-kb88凯时官网登录

来自:网络
时间:2023-05-17
阅读:
免费资源网 - https://freexyz.cn/
目录

一、问题

最近在做代码重构,代码工程采用了controller/service/dao分层架构,dao层使用了mybatis-plus框架。
在查看service层时发现如下代码:

@service
public class sampleserviceimpl implements sampleservice {
    @resource
    private samplemapper samplemapper;
    @override
    public sampleto findbyid(long id) {
        sample sample = this.samplemapper.selectone(wrappers.lambdaquery()
                //仅查询指定的column
                .select(sample::getid, sample::getname, sample::getdate)
                //查询条件 id = #{id}
                .eq(sample::getid, id)
        );
        return (sampleto) baseassembler.populate(sample, new sampleto());
    }
    @override
    public pageinfo findlistbydto(samplequerydto samplequerydto) {
        //开启分页
        pagehelperutil.startpage(samplequerydto);
        //查询分页列表
        list samplelist = this.samplemapper.selectlist(wrappers.lambdaquery()
                //查询条件 id = #{id}
                .eq(objects.nonnull(samplequerydto.getid()), sample::getid, samplequerydto.getid())
                //查询条件 name like concat('%', #{name}, '%')
                .like(stringutils.hastext(samplequerydto.getname()), sample::getname, samplequerydto.getname())
                //查询条件 type = #{type}
                .eq(stringutils.hastext(samplequerydto.gettype()), sample::gettype, samplequerydto.gettype())
                //查询条件 date >= #{startdate}
                .ge(objects.nonnull(samplequerydto.getstartdate()), sample::getdate, samplequerydto.getstartdate())
                //查询条件 date <= #{enddate}
                .le(objects.nonnull(samplequerydto.getenddate()), sample::getdate, samplequerydto.getenddate()));
        //转换分页结果
        return pagehelperutil.convertpageinfo(samplelist, sampleto.class);
    }
    @override
    public list findlistbycondition(string name, string type) {
        list samplelist = this.samplemapper.selectlist(wrappers.lambdaquery()
                //查询条件 name like concat('%', #{name}, '%')
                .like(stringutils.hastext(name), sample::getname, name)
                //查询条件 type = #{type}
                .eq(stringutils.hastext(type), sample::gettype, type)
        );
        return baseassembler.populatelist(samplelist, sampleto.class);
    }
	@override
    public sampledetailto finddetailbyid(long id) {
        return this.samplemapper.finddetail(id);
    }
    @override
    public integer add(sampleadddto sampleadddto) {
        sample sample = new sample();
        baseassembler.populate(sampleadddto, sample);
        return this.samplemapper.insert(sample);
    }
}

dao层代码:

public interface samplemapper extends basemapper {
	//sql脚本通过xml进行定义
    sampledetailto finddetail(@param("id") long id);
}

如上service代码中直接使用mybatis-plus框架提供的wrapper构造器,写的时候是挺爽,不用再单独为samplemapper接口写xml脚本了,直接在service类中都完成了,但是我不推荐这种写法。

分层架构的本意是通过分层来降低、隔离各层次的复杂度,
各层间仅通过接口进行通信,层间仅依赖抽象接口,不依赖具体实现,
只要保证接口不变可以自由切换每层的实现。

上述service类中直接引用了dao层实现框架mybatis-plus中的wrappers类,尽管servcie层依赖了dao层的mapper接口,但是mapper接口中的参数wrapper却是dao层具体实现mybatis-plus所独有的,试想我们现在dao层用的mybatis-plus实现,后续如果想将dao层实现切换为spring jpa,那mybatis-plus中wrapper是不都要替换,那servcie层中的相关wrapper引用也都要进行替换,我们仅是想改变dao实现,却不得不把servcie层也进行修改。同时service层本该是写业务逻辑代码的地方,但是却耦合进了大量的wrapper构造逻辑,代码可读性差,难以捕捉到核心业务逻辑。

二、优化建议

那是不是mybatis-plus中的wrapper就不能用了呢?我的答案是:能用,只是方式没用对。
wrapper绝对是个好东西,方便我们构造sql,也可以将我们从繁琐的xml脚本中解救出来,但是不能跨越层间界限。

优化建议如下:

  • 移除servcie中的wrapper使用
  • java8 之后接口提供了默认方法的支持,可通过给dao层mapper接口添加default方法使用wrapper
  • 单表相关的操作 - 通过dao层mapper接口的default方法直接使用wrapper进行实现,提高编码效率
  • 多表关联的复杂操作 - 通过dao层mapper接口和xml脚本的方式实现

优化后的service层代码如下:

@service
public class sampleserviceimpl implements sampleservice {
    @resource
    private samplemapper samplemapper;
    @override
    public sampleto findbyid(long id) {
        sample sample = this.samplemapper.findinfobyid(id);
        return (sampleto) baseassembler.populate(sample, new sampleto());
    }
    @override
    public sampledetailto finddetailbyid(long id) {
        return this.samplemapper.finddetail(id);
    }
    @override
    public pageinfo findlistbydto(samplequerydto samplequerydto) {
        //开启分页
        pagehelperutil.startpage(samplequerydto);
        //查询分页列表
        list samplelist = this.samplemapper.findlist(samplequerydto);
        //转换分页结果
        return pagehelperutil.convertpageinfo(samplelist, sampleto.class);
    }
    @override
    public list findlistbycondition(string name, string type) {
        list samplelist = this.samplemapper.findlistbynameandtype(name, type);
        return baseassembler.populatelist(samplelist, sampleto.class);
    }
    @override
    public integer add(sampleadddto sampleadddto) {
        sample sample = new sample();
        baseassembler.populate(sampleadddto, sample);
        return this.samplemapper.insert(sample);
    }
}

优化后的dao层代码:

public interface samplemapper extends basemapper {
    default sample findinfobyid(long id) {
        return this.selectone(wrappers.lambdaquery()
                //仅查询指定的column
                .select(sample::getid, sample::getname, sample::getdate)
                //查询条件 id = #{id}
                .eq(sample::getid, id)
        );
    }
    default list findlist(samplequerydto samplequerydto) {
        return this.selectlist(wrappers.lambdaquery()
                //查询条件 id = #{id}
                .eq(objects.nonnull(samplequerydto.getid()), sample::getid, samplequerydto.getid())
                //查询条件 name like concat('%', #{name}, '%')
                .like(stringutils.hastext(samplequerydto.getname()), sample::getname, samplequerydto.getname())
                //查询条件 type = #{type}
                .eq(stringutils.hastext(samplequerydto.gettype()), sample::gettype, samplequerydto.gettype())
                //查询条件 date >= #{startdate}
                .ge(objects.nonnull(samplequerydto.getstartdate()), sample::getdate, samplequerydto.getstartdate())
                //查询条件 date <= #{enddate}
                .le(objects.nonnull(samplequerydto.getenddate()), sample::getdate, samplequerydto.getenddate())
        );
    }
    default list findlistbynameandtype(string name, string type) {
        return this.selectlist(wrappers.lambdaquery()
                //查询条件 name like concat('%', #{name}, '%')
                .like(stringutils.hastext(name), sample::getname, name)
                //查询条件 type = #{type}
                .eq(stringutils.hastext(type), sample::gettype, type)
        );
    }
    //sql脚本通过xml进行定义)     
    sampledetailto finddetail(@param("id") long id);
}

优化后的servcie层完全移除了对wrapper的依赖,将servcie层和dao层实现进行解耦,同时dao层通过java8 接口的默认方法同时支持wrapper和xml的使用,整合编码和xml脚本的各自优势。

三、repository模式

经过优化过后,service层代码确实清爽了许多,移除了mybatis-plus的wrapper构造逻辑,使得service层可以更专注于业务逻辑的实现。但是细心的小伙伴还是会发现servcie层仍旧依赖了mybatis的分页插件中的pagehelper类、pageinfo类,pagehelper插件也是技术绑定的(强绑定到mybatis),既然我们们之前强调了servcie层与dao层间的界限,如此在servcie层使用pagehelper也是越界了,例如后续如果切换spring jpa,那pagehelper在servcie层的相关的引用也都需要调整。

真正做到业务和技术解耦,可以参考ddd中的repository(仓库、资源库)模式

  • 单独定义通用的分页查询参数dto、分页查询结果dto(与具体技术解耦)
  • 定义repository接口,仅依赖聚合、通用分页查询参数dto、分页查询结果dto
  • 定义repository接口的实现类,具体实现可依赖如mybatis、jpa等dao框架,在repository的具体实现类中完成转换:
    • 领域模型(聚合)<==> 数据实体
    • 通用分页查询参数dto、结果dto <==> dao框架的分页参数、结果(如pagehelper、ipage等)

ddd映射到代码层面,改动还是比较大的,所以在这次重构代码的过程中并没有真正采用ddd repository模式,
而是仅从servcie中移除mybatis-plus wrapper便结束了,虽没有完全将service层与dao层实现(pagehelper)解耦,
但在service层移除wrapper构造逻辑后,使得service层代码更清爽,可读性更好了,重构过程的代码改动量也在可接收的范围内。

免费资源网 - https://freexyz.cn/
返回顶部
顶部
网站地图