请直接看原文
原文链接:多线程与数据库事务以及数据库连接之间的关系 - 知乎 (zhihu.com)
--------------------------------------------------------------------------------------------------------------------------------
今天我们来梳理一下, 多线程、数据库事务、数据库连接之间的关系
单线程下
先来看一段代码
@Transactional@Overridepublic void updateTest(Test updateVO) {Test test = testMapper.selectByPrimaryKey(updateVO.getId());System.out.println("当前线程是: "+Thread.currentThread().getName()+"查出来的值是"+JSON.toJSON(test).toString());testMapper.updateByPrimaryKey(updateVO);testMapper.deleteByPrimaryKey(2);}
这段代码说明了什么?
- 开启了事务
- 其中有三次和数据库交互的操作
问题来了,这三个与数据库的操作,与数据库建立的连接是同一个吗?还是不同的连接呢?
- 开启事务的话,建立一次连接 :控制台输出Fetched SqlSession的字样
- 没开启事务的话,建立三次连接 :控制台输出Creating a new SqlSession的字样
为什么会这样呢,就是因为 我们经常说的事务
假如说,当我们有一个线程A来执行此方法时,发现此方法开启了事务, 而事务,又是基于数据库Connection连接的,这个事务中有三个操作数据库的dao方法,此时线程A会用同一个connection连接操作这三个dao方法.
我们再来看下事务,假如说程序有一个方法,一个方法里调了两个接口方法,每个接口方法都开启了事务,每个接口都有三个dao方法的操作.如下面类似的代码
结果就是如下图:一个线程对应一个connection数据库连接, 这个连接上可以有两个事务,且两个事务都能正常执行且互不影响.
多线程下
假如说有两个线程同时进入这个接口,线程操作数据库里数据时,那么他们的关系又会是什么样的呢?
从图中我们可以看到,两个线程分别获得不同的数据库连接,各自有各自的事务,这个时候,就是前文说的多事务
总结
1.同一时刻,不同的线程会获取到不同的数据库连接Connection对象,各自开启各自的事务, 每个事务之间是由mysql自己来实现事务的隔离性的.
2.开启事务后,为什么三个dao方法可以获得同一个Connection?
当前线程把connection对象存到了ThreadLocal中, ThreadLocal 中保存了一个 map,key 是DataSource数据源,value 是数据库连接Connection。当一个线程多次操作数据库的时候(很多个dao),每次都可以获得同一个数据库连接.
3.为什么要确保是同一个数据库连接?
是因为数据库的事务是基于数据库连接的,如果这个线程操作了三次dao每次连接都不一样,那么就没办法保证这三次操作被同一个事务所管理.
4.什么是本地事务?
就是几个dao方法只被一个线程操作,然后就只产生了一个connection连接对象. 这才能就是说是本地事务.