记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查

一、背景描述

项目要求update/delete必须要有where条件(因为出了一次生产上把一张表的数据全表删除的严重生产事故),并且要打印出where中的条件,所以考虑用mybatis拦截器处理

mybatis拦截器实现原理简述

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第1张图片

在Mybatis中,拦截器可拦截如上图中四种相关操作类的操作方法。通过阅读源码可知,执行顺序为: Executor -> StatementHandler -> ParameterHandler -> StatementHandler -> ResultSetHandler

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第2张图片

其中:StatementHandler类中包含针对query、update操作的具体拦截方法。因此,拦截基于StatementHandler类进行。

删除或更新拦截器SafeDeleteOrUpdateInterceptor部分代码

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第3张图片

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第4张图片

在加这个拦截器前,项目中还有一个针对select特殊字符处理的StatementHandler拦截器-MySqlInterceptor

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第5张图片

执行sql时报错

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第6张图片

 具体是在执行findById方法时报错,findById最后是调用到mybatis的selectOne方法报错。奇怪的是我本地在eclipse启动项目不会有这个报错,打成jar包就有这个报错?

二、开始排查

看报错信息,一开始没有什么头绪,因为是第一次遇到这种错,也是做各种尝试,先是在网上查了这个报错,大部分说是jar包冲突

2.1检查jar包冲突

先看项目中有没有mybatis的包冲突,发现没有记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第7张图片

 因为delete/update拦截器用到了github的jsqlparse,于是再检查jsqlparse的包有没有冲突,发现也没有

2.2既然没有jar包冲突,那应该是代码问题, 因为我本地不会报错不好调试,但是看报错信息应该是拦截器那里导致了问题,于是考虑分别注释掉其中一个拦截器试试

注释原来的MySqlInterceptor留下SafeDeleteOrUpdateInterceptor,没有报错,说明SafeDeleteOrUpdateInterceptor本身没什么问题

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第8张图片

注释SafeDeleteOrUpdateInterceptor留下原来的MySqlInterceptor,也没有报错

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第9张图片

 但是两个拦截器就会报错,然后去github上搜了下,找到一篇相关文章,说的是获取StatementHandler对象时的问题,于是考虑两个拦截器获取StatementHandler对象有什么不一样

MySqlInterceptor是直接强转

 SafeDeleteOrUpdateInterceptor是参照mybaits-plus PluginUtils的写法

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第10张图片

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第11张图片

既然mybatis-plus是如上的写法,于是考虑把MySqlInterceptor获取StatementHandler对象改成一样的。本地调试发现,确实存在invocation的target还是代理对象,因此需要进一步获取具体的对象

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第12张图片

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第13张图片

在只有其中的某一个拦截器时,invocation的target就是StatementHandler对象

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第14张图片

 三、总结和思考

为什么同种对象如果存在多种拦截器对象时会出现invocation的target还是代理对象的情况,具体我也不是太清楚,没有具体研究源码,但是根据mybatis拦截器机制猜测,如果同种对象存在多种拦截器时,首先有个执行顺序,

四、为什么我本地不报错

原因尚不清楚

五、两个拦截器的执行顺序

在第3点中简要说到同种对象如果存在多种拦截器顺序问题,可参考同行总结的内容

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第15张图片

记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第16张图片 记录mybatis插件奇怪报错问题There is no getter for property named ‘delegate‘ in ‘class com.sun.proxy.$Proxy的排查_第17张图片

 本地验证(gif动图)

plugin加载顺序验证

结果是先执行SafeDeleteOrUpdateInterceptor,再执行MySqlInterceptor。加载顺序的话应该就是先加载MySqlInterceptor再加载SafeDeleteOrUpdateInterceptor

结尾:如有不足,还请大家多多指出

你可能感兴趣的:(mybatis,maven,java)