一:文章背景
本文从源码的角度进行分析Mybatis-Plus,为了阅读且吸收的更顺利,希望读者有以下基础:
- 对Java、Spring、Mybatis、Mybatis-Plus有一定的了解/使用基础
- 对底层源码有略微学习,哪怕是为了框架二开、框架扩展或知识储备
- 本文章参考源码 3.4.2
二:问题带入
使用过Mybatis-Plus的同学都知道不需要写xml即可使用默认的【单表】的增删改查及单表的复杂查询。
请思考以下问题:
- 为什么用了Mybatis-Plus就不需要写xml文件,只需要写一个接口继承BaseMapper?
- 在什么时候Mybatis-Plus将动态sql预埋了、预埋的字段内容有哪些?
- 如何优雅的新增自定义Mapper内置方法?
三:源码分析
先回答以上三个问题
3.1 为什么用了Mybatis-Plus就不需要写xml文件,只需要写一个接口继承BaseMapper?
总所周知:
1.Mybatis通过动态代理Mapper接口方法/SqlSession两种形式暴露给业务使用,其中Mapper接口的方式使用较多。
2.可以通过原生SqlSessionFactory.getMapper(),或者通过spring版本的Mybatis通过将MapperFactoryBean封装原生的Mapper生成Bean供业务访问。
同时,Mybatis-Mapper和xml的关系
Mybatis在扫描Xml时会根据namespace是否是接口来解决是否对接口生成动态代理,也就是我们理解的Mapper接口。
回答此问题:
生成Mapper接口的方法有两种:
1.扫描xml,将其Namespace对应的接口Configuration的addMapper方法生成动态代理Mapper接口。2.spring版本mybatis,扫描Mapper接口,生成对应的MapperFactoryBean,其继承了DaoSupport接口并在其实现了InitializingBean接口方法中调用Configuration的addMapper方法,生成Mapper接口
3.mybatis-plus是通过重写Configuration的addMapper方法,在其扫描Mapper接口时,通过对BaseMapper中预埋的增删改查方法进行添加到Mybatis的MappedStatement。使得用户调用Mapper接口方法时能够找到其对应的MappedStatement。
补充:MappedStatement是Namespace下每个方法的映射对象。
3.2: 在什么时候Mybatis-Plus将动态sql预埋了、预埋的字段内容有哪些?
代码调用链路图
生成的预埋sql是什么样的呢?我们拿SelectList举例
主要有三部分组成:
1.QueryWrapper.sqlSelect:查询指定列,用于区分用户是否查询指定列,还是全列查询
2.AbstractWrapper.entity :实体部分,用ew.entity在动态sql中调用,此处用来等值查询(Update语句时,此字段用来做set更新字段)
3.Wrapper.sqlSegment: 此部分为动态条件(and、or、group、having、orderby)等条件生成的sql语句
动态sql代码组成
BaseMapper参数设置
QueryWrapper承接用户参数
综上所述可以总结:
场景:用户使用QueryWrapper调用Mapper接口进行SelectList查询
调用链路:
1.项目启动时已经生成了预埋的动态sql方法及MappedStatement
2.用户通过构造Querywrapper生成动态条件,即动态sql中【ew】字段属性
3.通过调用父类BaseMapper接口方法走向Mapper接口动态代理,进而走向Mybatis的Sqlsession执行。