文章目录
ThreadLocal介绍
- 在实际开发中,我们用MyBatis框架获取SqlSession应该是属于Dao层代码,不允许出现在Service层中,如果dao层数据应用到services层,就提高了耦合度,我们需要删除service层对Mybastis依赖(dao层)
- ThreadLocal是java.lang.ThreadLocal 该类提供了线程局部 (thread-local) 变量,用于在**当前线程中共享数据
回顾线程了解ThreadLocal
我们知道 进程是资源的分配单位,线程是运行调度单位。任何运行的程序,必定归属于某个线程。不管是main线程/gc线程还是其他线程。
程序运行的时候就会产生一个线程,线程里面有一个Context上下文,获取线程上下文的方式:Thread.currentThread().getContext();
(返回类型ThreadContext)
在JDK中线程上下文只有使用的时候才会去创建,而创建线程的上下文就是通过ThreadLocal来实现。
ThreadLocal是线程上下文context的代理对象,主要是用来存放数据(通过get和set方法),它是底层是一个基于Map键值对形式存储数据的,而ThreadLocal调用set方法存储数据的时候,它的key就是存放它自己(this-当前的线程)。
ThreadLocal特点
- ThreadLocal工具类底层就是一个Map键值对形式,key存放的当前线程(this),value存放需要共享的数据(只能在相同线程间共享数据)。
- 使用哪个线程存储的数据,只能通过该线程取出(存放进去数据的线程)
- ThreadLocal 是保证了多线程环境下数据的独立性(不同线程之间数据是不共享的,只有同一个线程数据共享)
通过ThreadLocal来装载MyBatis对象的SqlSession实现service和dao层解耦
改造SqlSessionUtils2:
//sqlSession工具类,获取sqlSession
public class SqlSessionUtils2 {
private static SqlSessionFactory sqlSessionFactory;
//static 静态代码,在类加载的时候执行一次,且只执行一次
static{
//1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//2. 加载mybatis-config.xml配置文件 参数:核心配置文件
InputStream inputStream = SqlSessionUtils.class.getClassLoader().getResourceAsStream("com/xgf/mybatisdemo/config/mybatis-config.xml");
//3. 创建SqlSessionFactory对象 加载核心配置文件 参数:输入流
sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
//通过ThreadLocal改造
//A: 定义一个ThreadLocal集合,本质是Map<Thread,Object> map
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();//这个key默认是当前线程,value就是传入的参数SqlSession类型
public static SqlSession getSession() {
//查找在当前线程中,是否有对应的SqlSession
SqlSession sqlSession = threadLocal.get(); //相当于map.get(Thread.currentThread())
if (sqlSession != null) {
//当前线程存在SqlSession直接返回给调用者使用
return sqlSession;
} else {
//没有就创建一个新的,并且保存在当前线程中
sqlSession = sqlSessionFactory.openSession();
//保存
threadLocal.set(sqlSession);//实际存储的是threadLocal.set(Thread.currentThread(),sqlSession)
return sqlSession;//返回
}
}
public static void commitAndClose() {
//进行修改表操作,需要提交sqlSession才能更新数据库,定义这个方法
SqlSession sqlSession = threadLocal.get();
if (sqlSession != null) {
sqlSession.commit();//提交
sqlSession.close();//关闭
//已经关闭的session不能留在threadLocal中
//所以要删除
threadLocal.remove();
}
}
//出现错误,回调
public static void rollbackAndClose() {
SqlSession sqlSession = threadLocal.get();
if (sqlSession != null) {
sqlSession.rollback();//回滚
sqlSession.close();//释放
//已经关闭的session不能留在local
//所以要删除
threadLocal.remove();
}
}
//通过该方法实现dao和service解耦
public static <T> T getMapper(Class className) {
return (T) getSession().getMapper(className);
}
}