项目架构升级史-架构2.1
在架构3.0中,已经说明了2.0的关于数据库字段修改的问题.
3.0是直接使用nosql解决这个问题, 那能不能即使用mysql和mybatis也能解决数据库字段修改的问题.
那么现在的问题就是: 修改了数据库字段,mybatis的sql能自动变成相应的sql.
为了解决这个问题, 自然而然就想到了动态修改 Mapper上注解中的sql语句. 想到曾经看到过mybatis plus好像也是继承BaseMapper,并不需要写Select 等注解, 就已经有了增删改查的能力.
通过研究mybatis和mybatis plus的源码, 再结合<<深入浅出MyBatis技术原理与实战>>这本书很快就明白了mybatis和plus的原理.
我现在要做的是, 类似 mybatis plus 继承BaseMapper 所有mapper都有增删改查的能力,并且数据库字段的修改不需要修改mapper.
那为什么不直接使用plus呢?
1 plus的核心也是修改mybatis的源码, 再整合自己的代码,很多功能我并不需要 .
2 我的核心还是使用mybatis只不过需要mapper自带这些基础增删改查.
那么就需要完成以下两个功能
1 提供动态增删改查sql
这个好说,以前sql的自动生成是从word文档读取生成的,那么如果想获取准确的sql只需要从数据库中获取每一个表的字段,通过拼接即可生成准确的sql, 写一个工具类即可.
这个Sql类保存一个map包含所有表的sql语句.
比如key是"UserMapper.getInfo" value是"select * from user".
Sql.printSql("表名") 即可打印存储的sql.

2 动态替换sql
那么就需要知道mybatis是怎么加载mapper以及怎么使用Select注解上的sql的.
mybatis是通过MapperAnnotationBuilder这个类加载基于注解的mapper.
其中type就是自定义mapper的class类, 例如UserMapper的class .(java中是UserMapper.class, kotlIn中是UserMapper::class.java)
这里的意思是遍历这个class类的方法, 然后解析方法上注解的字符串.

LanguageDriver也可以动态替换sql, mybatis官方文档有详细讲解.一开始使用这个但是不能动态获取mapper的类名.
SqlSource就是保存具体sql语句的地方,sql就是实际的sql语句了.


简单来说, 就是 mybatis 找到所有包下面的带有@Mapper注解的接口, 然后遍历它的方法, 取出方法上注解的sql存起来.
如果想动态替换sql 只需要修改buildSqlSourceFromStrings方法, 根据sql的值替换成实际的sql即可.
2.1 改写baseMapper
我们改写buildSqlSourceFromStrings方法, 如果发现是BaseModel 开头的sql语句, 那么就需要替换成实际sql语句.
但是怎么知道要替换成哪一个表的sql呢, 所以有个规定 UserMapper 对应的是user表,根据mapper的类名替换.
在buildSqlSourceFromStrings方法里取到该mapper的类名, 以BaseModel.getInfo为列,先把BaseModel.getInfo替换成 UserMapper.getInfo, 因为在Sql类已经存了UserMapper.getInfo的sql语句.再把UserMapper.getInfo替换成实际的sql语句.

2.2 怎么修改mybatis源码
很简单,在项目源码文件夹建立一个包名类名相同的类, 虚拟机在加载java类的时候会优先加载src下面的类.
以下就是修改的三个地方

removeMethod方法是为了, 如果重载了getInfo 方法, mybatis就会报错, 因为父类和子类都有getInfo方法, 并且这两个getInfo上的注解都有sql, 就不知道用哪一个了. removeMethod就是如果子类重载了方法, 就去除掉父类的方法.


实际效果
VisibilityMapper直接继承BaseMapper 没有sql语句.

默认有一行记录.

执行测试用例.

记录增加.

新增一个字段 test 并赋值.

现在只需在代码中的model增加一个字段test.

再次执行测试用例, 输出中自动带上了test, 插入的时候也带上了test.


至此大功告成. 这样有点像mybatis和hibernate的结合体, 既有hibernate面向对象操作数据库的功能又保留了
mybatis操作sql的灵活性.
完成这个功能有两大难点
1 源码的理解
因为第二家公司是华为外包, 所以接触到了华为的项目,那是一个历史悠久的大项目, 源码多的吓死人, 为了搞清原理,研究过项目源码,所以mybatis的源码量相对华为的还是很小的,也远没有华为的复杂.所以看mybatis和plus的源码过程是比较简单的.
2 修改源码
这也是因为华为的项目,当时有个需求需要把他们的web端部署到websphere上,但是它使用的axis2框架一直有问题,所以那时天天研究websphere的类加载机制.还有就是华为的web框架没有源码, 但是我要调试需要知道里面到底是怎么执行的,所以把需要调试的类放到自己src路径下增加调试语句,就可以清楚的知道这个类是干什么的.
所以有时候看到网上说外包这不好那不好,但是我在外包的这一段经历,给了我很大的成长,也是在那里知道了我认为作为程序员最重要的思想-自动化.也因此把自动化思想全应用在了现在的公司.
任何公司都有它的优点和缺点,作为一个员工,我们踏踏实实做好自己的事,闲暇的时候多学习,开阔自己的眼界,不仅是学习技术,还要多学习为人处世的能力.