Mybatis随笔(四) 异常处理ErrorContext

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis随笔(四) 异常处理ErrorContext相关的知识,希望对你有一定的参考价值。

参考技术A Mybatis 使用 ErrorContext 来做异常的统一处理

大体上就是使用一个 ThreadLocal<T> 来存储当前线程的异常信息,当异常发生时可以根据这些信息快速地定位问题,一目了然

先贴下源码

其实都很易读,精髓就是那个 ThreadLocal<ErrorContext> 类型的类变量 LOCAL .

看下其方法

一个私有的构造方法,是一个单例模式的应用,通过 ThreadLocal 实现

ThreadLocal 是一块线程私有的领地,可以随时从线程上下文中拿到这份变量的副本,是多线程下安全访问共享变量的一种解决方案。

1.4 引入,但其返回的都是Object类型对象,需要强转;在 1.5 时添加泛型后得到了极大的增强

关于 ThreadLocal 其大名鼎鼎的就是可能会造成内存泄漏,详细可参考 ThreadLocal内存泄漏真因探究

而 ErrorContext 就是一种很好的 ThreadLocal 应用实例。

resource / activity / object / message / sql / cause 这些方法都是会使用到 ErrorContext 的地方,也就是会创建 ThreadLocal

如果你跟着调用链往上追溯,都会是下面三个点

清理方法是 reset ,看下调用

与使用对应,再看下具体调用方式

其他的都是一样,通过 try-catch-finally 的方式确保 ThreadLocal 的释放

除了以上方法,我们注意到还有两个特殊方法 store 和 recall
ErrorContext 还有一个属性用于存储自身

将当前对象保存起来,同时新建一个 ErrorContext 返回

很明显,恢复之前存储起来的 ErrorContext

再来看下调用

发现是在 KeyGenerator # processBefore 方法前后调用的,很明显是怕此方法污染了异常信息,具体原因需要再深入看下这个方法。

可参考 mybatis 源码分析 KeyGenerator 详解

这里对比一下另一种写法(应该是低版本的实现,其实无所谓什么版本,只要能触发我们思考就值得讲一讲)

这种写法会有什么问题吗?

首先我们明确几点

那么上述写法就做了如下三件事
第一步 A@ErrorContext.stored = A@ErrorContext
第二步 新建 ErrorContex 对象 B@ErrorContext
第三步 将 B@ErrorContext 放入 ThreadLocal

这里请注意一下, B@ErrorContext.stored 是空的
那么下次调用 recall 方法来恢复的时候还能拿到 stored 下来的对象吗?
是拿不到的。

ThreadLocal内存泄漏真因探究
Mybatis源码研究之ErrorContext
mybatis 源码分析 KeyGenerator 详解

MyBatis异常处理org.apache.ibatis.executor.ExecutorException

由于测试缘故,数据库被加入了很多测试数据。再次执行原来的查询出现了异常org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorException: Statement returned more than one row, where no more than one was expected.

通过描述可以看到,期待返回结果数应该小于等于1,但却返回多条记录。开始由于查询返回的对象是A,检查了一下A发现没有重复记录,随后发现A类内部有成员B。

class A
    B b;

而在Mapper中的定义的Sql中查询b是返回唯一的结果,而不是一个List。因此是在查询b的时候造出现了异常。最后清理掉数据,异常解决。 所以当遇到这种异常时候不但要关注查询返回结果时候唯一,还要注意所查询的结果中包含的成员对象是否允许有多个。

以上是关于Mybatis随笔(四) 异常处理ErrorContext的主要内容,如果未能解决你的问题,请参考以下文章

随笔15 java中的异常类

SpringBoot系列优雅的处理统一异常处理与统一结果返回

MyBatis异常处理org.apache.ibatis.executor.ExecutorException

spring-mybatis整合项目 异常处理

关于Mybatis的java.lang.UnsupportedOperationException异常处理

mybatis 异常处理:Invalid bound statement (not found)