Spring 事务 数据库连接获取和释放原理
##调试demo
@Service
public class CrmUserService {
@Autowired
private CrmUserDao crmUserDao;
@Autowired
private CrmLoginLogDao crmLoginLogDao;
@Transactional
public void getUser() {
System.out.println("Service::"+Thread.currentThread().getName());
System.out.println(crmUserDao.getUser());
System.out.println(crmLoginLogDao.getLoginLog());
}
}
@Mapper
public interface CrmLoginLogDao {
@Select("select user_name from login_log")
public List<String> getLoginLog();
}
@Mapper
//@DS("slave")
public interface CrmUserDao extends BaseMapper {
// @Select("select version_code from t_app_update")
// @Select("select pg_sleep(1200)")
@Select("select user_name from user_info")
public List<String> getUser();
}
##目标方法被代理
##创建事务 createTransactionIfNecessary
##tm.getTransaction
##获取事务doGetTransaction()
##获取事务数据库连接,ConnectionHolder TransactionSynchronizationManager.getResource(obtainDataSource())
##获取数据源TransactionSynchronizationUtils.unwrapResourceIfNecessary(key)
##获取Object value = doGetResource(actualKey)
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
线程首次获取到值为空
##transaction 中属性ConnectionHolder为空
##开始事务
##判断txObject.hasConnectionHolder()是否有ConnectionHolder 为false,创建ConnectionHolder
##ConnectionHolder 设置到DataSourceTransactionManager,连接事务自动提交改为false
##事务中第一次sql查询,调用mapper查询
public abstract java.util.List com.newland.mi.dao.CrmUserDao.getUser()
##获取连接
Connection connection = getConnection(statementLog);
##从事务中获取连接
Connection connection = transaction.getConnection()
##从之前ConnectionHolder获取连接
return conHolder.getConnection();
##事务中第二次sql查询,调用mapper查询
public abstract java.util.List com.newland.mi.dao.CrmLoginLogDao.getLoginLog()
##从事务中获取连接
##查询完成,清空事务
cleanupTransactionInfo(txInfo);
##提交事务,释放连接
commitTransactionAfterReturning(txInfo);
##提交事务
##清理资源
cleanupAfterCompletion(status);
##清理
##设置事务自动提交,设置事务隔离级别为空
con.setAutoCommit(true);
DataSourceUtils.resetConnectionAfterTransaction( con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
##释放数据库连接回连接池
DataSourceUtils.releaseConnection(con, this.dataSource);
##清空ConnectionHolder 的currentConnection为空
this.currentConnection = null;
##数据库连接放回连接池
doCloseConnection(con, dataSource);
##数据库连接池
##connection.recycle();
##最终放入池内
##加锁,放回DruidConnectionHolder[]数组
private volatile DruidConnectionHolder[] connections;
##放入数组最后一个位置
incrementPoolingCount() 数组长度加1