大体上就是使用一个 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不能向数据库里面插入数据原因可能是执行了插入动作,但是没有最终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这种结构,这里需要注意一下。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)