时间:2021-07-01 10:21:17 帮助过:189人阅读
在现有的项目中,我们在public方法上面使用了@Transactional注解,当有线程调用此方法时,Spring会首先扫描到@Transactional注解,进入DataSourceTransactionManager继承自AbstractPlatformTransactionManager的getTransaction()方法,在getTransaction()方法内部,会调用doGetTransaction()方法,@Transactional的注解中,存在一个事务传播行为的概念,即propagation参数,默认等于PROPAGATION_REQUIRED,表示如果当前没有事务,就新建一个事务,如果存在一个事务,方法块将使用这个事务,具体其他参数的意义请看下图:
在getTransaction方法中,DataSourceTransactionManager重写了isExistingTransaction()方法,用于判断当前是否存在事务,以下是其的源码:
?1 2 3 4 5 6 | @Override protected boolean isExistingTransaction(Object transaction) { logger.debug(Thread.currentThread().getName() + ">>>" + "DataSourceTransactionManager.isExistingTransaction()" ); DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; return (txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive()); } |
但是,这几天我对源码进行调试的过程中,发现多线程并发的时候,isExistingTransaction方法总是返回的false,即ConnectionHolder总是为空,这是遇到的第一个疑问点,目前还没有弄清楚。由于源码判断当前不存在事务,所以总是会Creating new transaction,即新建一个事务。新建事务之后,会执行重写的doBegin()方法,在doBegin方法中,首先通过下面的代码判断了ConnectionHolder是否为空,如下:
?1 2 3 4 5 6 7 8 9 | if (txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { Connection newCon = this .dataSource.getConnection(); if (logger.isDebugEnabled()) { logger.debug(Thread.currentThread().getName() + ">>>" + "Acquired Connection [" + newCon + "] for JDBC transaction" ); } txObject.setConnectionHolder( new ConnectionHolder(newCon), true ); } |
这里会从当前配置的数据源中获取一个连接,然后设置相应的ConnectionHolder,接下来是关键的一步,也是存在的第二个问题点,拿到connection后,会首先判断connection的autoCommit属性是否为true,之前工作中在使用原始JDBC的时候,当进行事务的控制时,我们总是会首先设置autoCommit为false,禁止事务自动提交,然后commit提交事务,最后设置autoCommit为true。Spring Transaction也是这样进行管理的,但是问题来了, 先看源码:
?