什么是ThreadLocal
ThreadLocal是线程变量,填充的变量属于当前线程。对于其他线程是隔离的,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
如何使用ThreadLocal
/**
* @Author:cbx
* @Date:2020/10/13/16:27
*/
public class TestThreadLocal {
public static void main(String[] args) {
ThreadLocal<String> threadLocal=new ThreadLocal<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
threadLocal.set(Thread.currentThread().getName()+"-->"+Math.random());
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}).start();
}
}
}
set方法
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程中的map
ThreadLocalMap map = getMap(t);
if (map != null)
//把ThreadLocal作为key,value是设置的值
map.set(this, value);
else
createMap(t, value);
}
get方法
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程中的map
ThreadLocalMap map = getMap(t);
if (map != null) {
//获取value值,key是ThreadLocal对象
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
解决的问题(假设没有加入spring aop事务控制)
我们都知道mybatis中每个mapper都会对应一个connection,数据库的事务要么失败,要么成功,失败就回滚。
现在有这么一种情况。
Sevice方法里执行了两个不同的Mapper操作
因为操作了两个不同的mapper,就会有两个不同的Connection对象,那么其中一个操作失败后,不会影响另一个,但是在service中处在一个方法内,行为必须一致。
解决方法:使用同一个Connection对象
/**
* @Author:cbx
* @Date:2020/10/13/16:11
* 假设没有加aop事务控制
*/
@Service
public class TestServiceImpl implements TestService {
@Autowired
AccountMapper accountMapper;
@Autowired
private AddressMapper addressMapper;
@Override
public void test() {
accountMapper.transfer();
addressMapper.updateAdd();
}
}
解决方法
定义一个线程内共享的Connection
/**
* @Author:cbx
* @Date:2020/10/13/20:07
*/
public class ConnectionUtils {
public static ThreadLocal<Connection> threadLocal=new ThreadLocal<>();
public static Connection getConnection(){
Connection connection = threadLocal.get();
if (connection==null){
connection=new Connection();
}
return connection;
}
}
然后将每个mapper绑定到当前的Connection就能实现共享Connection