Mybatis随笔(四) 异常处理ErrorContext

Mybatis随笔(四) 异常处理ErrorContext,第1张

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 详解

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

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

首先我们明确几点

那么上述写法就做了如下三件事

第一步 [email protected] = A@ErrorContext

第二步 新建 ErrorContex 对象 B@ErrorContext

第三步 将 B@ErrorContext 放入 ThreadLocal

这里请注意一下, [email protected] 是空的

那么下次调用 recall 方法来恢复的时候还能拿到 stored 下来的对象吗?

是拿不到的。

ThreadLocal内存泄漏真因探究

Mybatis源码研究之ErrorContext

mybatis 源码分析 KeyGenerator 详解

mybatis不能向数据库里面插入数据原因可能是执行了插入动作,但是没有最终commit到数据库服务器导致。

mybatis插入数据的例子如下:

package com.mybatis.demo

import java.io.Reader

public class Test {

private static SqlSessionFactory sqlSessionFactory

private static Reader reader

static{

try{

reader = Resources.getResourceAsReader("Configuration.xml")

sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader)

}catch(Exception e){

e.printStackTrace()

}

}

public static SqlSessionFactory getSession(){

return sqlSessionFactory

}

//添加用户

public void addUser(){

User user = new User()

user.setId(4)

user.setUserAddress("人民广场")

user.setUserName("Birds")

user.setUserAge("102")

SqlSession session = sqlSessionFactory.openSession()

try{

IUserOperation userOperation = session.getMapper(IUserOperation.class)

session.commit()

System.out.println("当前增加的用户id为:"+user.getId())

}

finally{

session.close()

}

}

public static void main(String[] args) {

Test testUser = new Test()

testUser.addUser()

}

}

当执行到 testUser.addUser()后执行到session.commit()数据就会插入表。

使用Mybatis-plus时出现了org.apache.ibatis.binding.BindingException: Invalid bound statement (not found),这种原因:一般就是mapper没有找到mapper.xml中的方法,mybatis-plus去找方法是根据mapper所在的包去找mapper.xml,然后再根据mapper中方法名去找mapper.xml中对应的id的方法。有以下两种解决办法供大家参考:

方法一:

@MapperScan(basePackages ="com.test.mapper") 没有写此注解或者application.yml中没有配置mybatis.mapper-locations:classpath:com/test/mapper/*Mapper.xml。 这两处只要有一个地方配置就行了。

方法二:

查看编译的mapper目录和mapper.xml目录是否一样,目录一样才能找到mapper和mapper.xml对应的方法。这里注意一下:可能包名都是一样,但还是报这个问题,我就遇到过这种,这种就看是不是mapper.xml所在的文件夹是com.test.mapper而不是com/test/mapper这种结构,这里需要注意一下。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/sjk/6661166.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-26
下一篇 2023-03-26

发表评论

登录后才能评论

评论列表(0条)

保存