Spring5 源码阅读笔记(4.1.1.3)doBegin(transaction, definition) 开启事务

Spring5 源码阅读笔记(4.1.1)createTransactionIfNecessary(tm, txAttr, joinpointIdentification) 创建事务如有必要 讲述了创建事务的过程:

首先,创建事务对象,Spring5 源码阅读笔记(4.1.1.1)doGetTransaction() 拿事务对象

然后,判断是否已经有活跃的连接,如果有,Spring5 源码阅读笔记(4.1.1.2)handleExistingTransaction(definition, transaction, debugEnabled) 处理存在的事务

这一节,我们看看没有活跃连接的时候,即第一次创建事务切面,也就是创建的切面是最外层的。

首先,改写状态,将 newTransaction 设置为 true,然后就是本小节的方法 doBegin。

重点

  1. 从数据源获取连接,包装并放入事务对象中
  2. 关闭自动提交
  3. 设置事务状态为活跃 transactionActive = true
  4. 建立当前线程与(数据源,连接)的关系

在这里插入图片描述

@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;

	try {
		//如果没有数据库连接
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			//从连接池里面获取连接
			Connection newCon = obtainDataSource().getConnection();
			if (logger.isDebugEnabled()) {
				logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
			}
			//把连接包装成ConnectionHolder,然后设置到事务对象中
			txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		}

		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		con = txObject.getConnectionHolder().getConnection();

		//从数据库连接中获取隔离级别
		Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
		txObject.setPreviousIsolationLevel(previousIsolationLevel);

		// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
		// so we don't want to do it unnecessarily (for example if we've explicitly
		// configured the connection pool to set it already).
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			if (logger.isDebugEnabled()) {
				logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
			}
			//关闭连接的自动提交,其实这步就是开启了事务
			con.setAutoCommit(false);
		}

		//设置只读事务 从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!
		//设置只读事务就是告诉数据库,我这个事务内没有新增,修改,删除操作只有查询操作,不需要数据库锁等操作,减少数据库压力
		prepareTransactionalConnection(con, definition);

		//设置 事务是活跃的
		txObject.getConnectionHolder().setTransactionActive(true);

		int timeout = determineTimeout(definition);
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		// Bind the connection holder to the thread.
		if (txObject.isNewConnectionHolder()) {
			//如果是新创建的事务,则建立当前线程和数据库连接的关系
			TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
		}
	}

	catch (Throwable ex) {
		if (txObject.isNewConnectionHolder()) {
			DataSourceUtils.releaseConnection(con, obtainDataSource());
			txObject.setConnectionHolder(null, false);
		}
		throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
	}
}

跟 bindResource:
类 TransactionSynchronizationManager

public static void bindResource(Object key, Object value) throws IllegalStateException {
	Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
	Assert.notNull(value, "Value must not be null");
	Map<Object, Object> map = resources.get();
	// set ThreadLocal Map if none found
	if (map == null) {
		map = new HashMap<>();
		resources.set(map);
	}
							//(数据源,连接) 因为Spring可以有多个数据源
	Object oldValue = map.put(actualKey, value);
	// Transparently suppress a ResourceHolder that was marked as void...
	if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
		oldValue = null;
	}
	if (oldValue != null) {
		throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
				actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
	}
	if (logger.isTraceEnabled()) {
		logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
				Thread.currentThread().getName() + "]");
	}
}
发布了144 篇原创文章 · 获赞 250 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44367006/article/details/104682966