一、背景描述
项目要求update/delete必须要有where条件(因为出了一次生产上把一张表的数据全表删除的严重生产事故),并且要打印出where中的条件,所以考虑用mybatis拦截器处理
mybatis拦截器实现原理简述
在Mybatis中,拦截器可拦截如上图中四种相关操作类的操作方法。通过阅读源码可知,执行顺序为: Executor -> StatementHandler -> ParameterHandler -> StatementHandler -> ResultSetHandler
其中:StatementHandler类中包含针对query、update操作的具体拦截方法。因此,拦截基于StatementHandler类进行。
删除或更新拦截器SafeDeleteOrUpdateInterceptor部分代码
在加这个拦截器前,项目中还有一个针对select特殊字符处理的StatementHandler拦截器-MySqlInterceptor
执行sql时报错
具体是在执行findById方法时报错,findById最后是调用到mybatis的selectOne方法报错。奇怪的是我本地在eclipse启动项目不会有这个报错,打成jar包就有这个报错?
二、开始排查
看报错信息,一开始没有什么头绪,因为是第一次遇到这种错,也是做各种尝试,先是在网上查了这个报错,大部分说是jar包冲突
2.1检查jar包冲突
先看项目中有没有mybatis的包冲突,发现没有
因为delete/update拦截器用到了github的jsqlparse,于是再检查jsqlparse的包有没有冲突,发现也没有
2.2既然没有jar包冲突,那应该是代码问题, 因为我本地不会报错不好调试,但是看报错信息应该是拦截器那里导致了问题,于是考虑分别注释掉其中一个拦截器试试
注释原来的MySqlInterceptor留下SafeDeleteOrUpdateInterceptor,没有报错,说明SafeDeleteOrUpdateInterceptor本身没什么问题
注释SafeDeleteOrUpdateInterceptor留下原来的MySqlInterceptor,也没有报错
但是两个拦截器就会报错,然后去github上搜了下,找到一篇相关文章,说的是获取StatementHandler对象时的问题,于是考虑两个拦截器获取StatementHandler对象有什么不一样
MySqlInterceptor是直接强转
SafeDeleteOrUpdateInterceptor是参照mybaits-plus PluginUtils的写法
既然mybatis-plus是如上的写法,于是考虑把MySqlInterceptor获取StatementHandler对象改成一样的。本地调试发现,确实存在invocation的target还是代理对象,因此需要进一步获取具体的对象
在只有其中的某一个拦截器时,invocation的target就是StatementHandler对象
三、总结和思考
为什么同种对象如果存在多种拦截器对象时会出现invocation的target还是代理对象的情况,具体我也不是太清楚,没有具体研究源码,但是根据mybatis拦截器机制猜测,如果同种对象存在多种拦截器时,首先有个执行顺序,
四、为什么我本地不报错
原因尚不清楚
五、两个拦截器的执行顺序
在第3点中简要说到同种对象如果存在多种拦截器顺序问题,可参考同行总结的内容
本地验证(gif动图)
plugin加载顺序验证
结果是先执行SafeDeleteOrUpdateInterceptor,再执行MySqlInterceptor。加载顺序的话应该就是先加载MySqlInterceptor再加载SafeDeleteOrUpdateInterceptor文章来源:https://www.toymoban.com/news/detail-792062.html
结尾:如有不足,还请大家多多指出文章来源地址https://www.toymoban.com/news/detail-792062.html
到了这里,关于记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!