不同传播机制下怎么新建/获取事务
主线代码解析
当前源码基于spring boot 2.1.6.RELEASE版本
新建或者获取事务原理简述
从ThreadLocal<Map<DataSource,ConnectionHolder>中获取当前事务,获取到有效的数据库连接connectionHolder,说明当前存在事务
1.如果不存在事务
- 当前传播类型为MANDATORY抛出异常
- 当前传播类型为REQUIRESNEW,NESTED,REQUIRE,创建并启动事务
2.如果存在事务
- 当前传播类型为NEVER抛出异常
- 当前传播类型为NOT_SUPPORTED挂起当前事务,但是不启动新事务
- 当前传播类型为REQUIRESNEW 挂起当前事务,并且启动新事务
- 当前传播类型为SUPPORTED,MANDATORY,REQUIRES 继续使用当前事务,不需要挂起当前事务和启动新事务
3.启动事务做了什么
- 创建新的数据库连接
- 设置用户定义的或者spring定义的属性并且设置autocommit为false
- 把创建的数据连接放入ThreadLocal<Map<DataSource,ConnectionHolder>中
4.挂起事务做了什么
- 把当前数据库连接从ThreadLocal<Map<DataSource,ConnectionHolder>中清除保存在SuspendedResourcesHolder对象中
- 把当前数据库连接从其他描述数据库连接或者事务信息的ThreaLocal中清除保存在SuspendedResourcesHolder对象中
- 把SuspendedResourcesHolder对象存储在DefaultTransactionStatus对象中,以方便后面恢复事务
1.当前不存在事务,不同传播机制是如何处理的
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
//org.springframework.transaction.support.AbstractPlatformTransactionManager
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
//获取当前事务信息
Object transaction = doGetTransaction();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
//存在事务的处理
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
//不存在事务的处理
// 1.检查超时时间参数合法性,不合法抛出InvalidTimeoutException异常
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
//当前不存在事务,当前方法定义的事务传播类型为MANDATORY时抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
//当前不存在事务,当前方法定义的事务隔离级别为REQUIRES_NEW,PROPAGATION_NESTED,PROPAGATION_REQUIRED创建新的连接和事务
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
//当前不存在事务,当前方法定义的事务隔离级别为SUPPORTED,NOT_SUPPORTED NEVER spring不会创建连接和事务
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
2.当前存在事务,不同传播机制是如何处理的
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
//挂起事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
//新建事务
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
3.事务是怎么启动的
- 新建数据库连接
- 数据库连接属性同步,比如隔离级别,连接超时时间,是否只读
- 数据库连接设置autoCommit为false
- 以DataSource为key,数据库连接为value,放入ThreadLocal中
- 同步更新其他保存当前数据库信息或者属性的ThreadLocal变量值
下面的思维导图红色部分才是精华,想快速了解的只需要看红色部分
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction方法中开启事务的代码
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
Connection con = null;
try {
//没有数据库连接或者数据库连接属性SynchronizedWithTransaction为true,都会创建一个新的连接
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.obtainDataSource().getConnection();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
//设置新建的数库连接到transaction对象中,并设置isNewConnectionHolder为true,表示新创建的连接
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
//设置数据库连接属性SynchronizedWithTransaction为true
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
//@Transation设置的的隔离级别,是否只读同步到数据库连接
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
//设置数据库连接的autocommit为false
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
//只读的数据库连接执行SET TRANSACTION READ ONLY sql语句
this.prepareTransactionalConnection(con, definition);
//设置数据连接transactionActive为true,数据连接为活跃
txObject.getConnectionHolder().setTransactionActive(true);
//从transational属性中超时时间同步到数据库连接
int timeout = this.determineTimeout(definition);
if (timeout != -1) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
//如果是新建的连接,则把当前的数据连接放入threadLocal
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable var7) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.obtainDataSource());
txObject.setConnectionHolder((ConnectionHolder)null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
}
}
org.springframework.transaction.support.TransactionSynchronizationManager#bindResource
org.springframework.transaction.support.TransactionSynchronizationManager
以下变量,创建资源,挂起资源,恢复资源都需要更新
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
public static void bindResource(Object key, Object value) throws IllegalStateException {
//根据datasource创建一个对象为Key,数据库连接为value,放入threadLocal
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);
}
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() + "]");
}
}
org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction
@Nullable
public static Integer prepareConnectionForTransaction(Connection con, @Nullable TransactionDefinition definition) throws SQLException {
Assert.notNull(con, "No Connection specified");
//transation注解如果设置为只读,同步到连接
if (definition != null && definition.isReadOnly()) {
try {
if (logger.isDebugEnabled()) {
logger.debug("Setting JDBC Connection [" + con + "] read-only");
}
con.setReadOnly(true);
} catch (RuntimeException | SQLException var4) {
for(Throwable exToCheck = var4; exToCheck != null; exToCheck = ((Throwable)exToCheck).getCause()) {
if (exToCheck.getClass().getSimpleName().contains("Timeout")) {
throw var4;
}
}
logger.debug("Could not set JDBC Connection read-only", var4);
}
}
//transation的隔离级别同步到数据库连接
Integer previousIsolationLevel = null;
if (definition != null && definition.getIsolationLevel() != -1) {
if (logger.isDebugEnabled()) {
logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " + definition.getIsolationLevel());
}
int currentIsolation = con.getTransactionIsolation();
if (currentIsolation != definition.getIsolationLevel()) {
previousIsolationLevel = currentIsolation;
con.setTransactionIsolation(definition.getIsolationLevel());
}
}
return previousIsolationLevel;
}
org.springframework.jdbc.datasource.DataSourceTransactionManager#prepareTransactionalConnection
protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition) throws SQLException {
if (this.isEnforceReadOnly() && definition.isReadOnly()) {
Statement stmt = con.createStatement();
try {
stmt.executeUpdate("SET TRANSACTION READ ONLY");
} finally {
stmt.close();
}
}
}
org.springframework.transaction.support.AbstractPlatformTransactionManager.prepareSynchronization
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
definition.getIsolationLevel() : null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
}
}
4.事务是怎么挂起的
org.springframework.transaction.support.TransactionSynchronizationManager
以下变量,创建资源,挂起资源,恢复资源都需要更新
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction 片段
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction片段
看入参和出参数,入参数doGetTransaction获取DataSourceTransactionObject对象,挂起的资源存放在org.springframework.transaction.support.DefaultTransactionStatus对象中,getTransaction返回构建好的DefaultDefaultTransactionStatus对象
Object transaction = doGetTransaction();
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
//TransactionSynchronizationManager.synchronizationActive这个Threaclocal变量不为null
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 挂起Synchronizations
// 获取TransactionSynchronizationManager.synchronizations变量,并且依次调用变量存放的TransactionSynchronization的suspend方法
//清空synchronizations变量,并返回原来存放的synchronizations变量
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
//TransactionSynchronizationManager.currentTransactionName 存放事务名称设置为null
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
//TransactionSynchronizationManager.currentTransactionReadOnly设置为false
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
//TransactionSynchronizationManager.CurrentTransactionIsolationLevel 存放隔离级别设置为false
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
//TransactionSynchronizationManager.actualTransactionActive 设置为null
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
//把设置为null或者重新设置为默认值的threadLoal存储的构建成挂起资源返回
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
// Neither transaction nor synchronization active.
return null;
}
}
org.springframework.transaction.support.AbstractPlatformTransactionManager#doSuspendSynchronization
private List<TransactionSynchronization> doSuspendSynchronization() {
// 获取synchronizations变量(存放TransactionSynchronization),并且依次调用存放的TransactionSynchronization的suspend方法
List<TransactionSynchronization> suspendedSynchronizations =
TransactionSynchronizationManager.getSynchronizations();
for (TransactionSynchronization synchronization : suspendedSynchronizations) {
synchronization.suspend();
}
//清空synchronizations变量,并返回原来存放的synchronizations变量
TransactionSynchronizationManager.clearSynchronization();
return suspendedSynchronizations;
}
org.springframework.transaction.support.TransactionSynchronizationManager.clearSynchronization
public static void clearSynchronization() throws IllegalStateException {
if (!isSynchronizationActive()) {
throw new IllegalStateException("Cannot deactivate transaction synchronization - not active");
}
//清空synchronizations变量
logger.trace("Clearing transaction synchronization");
synchronizations.remove();
}
5.怎么获取当前事务
从Threalocal<Map<datasource,ConnectionHolder> 变量resources中根据dataSource获取对应的数据库连接
org.springframework.jdbc.datasource.DataSourceTransactionManager.doGetTransaction()
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
//设置是否允许使用savepoint技术
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
//从threadLocal中过去数据库连接
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
org.springframework.transaction.support.TransactionSynchronizationManager.getResource
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
org.springframework.transaction.support.TransactionSynchronizationManager.doGetResource
@Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
org.springframework.jdbc.datasource.DataSourceTransactionManager.isExistingTransaction
判断存在不存在事务,其实就是判断Thread<Map<DataSource,ConnectionHolder> resources 中有没有有效的数据库连接
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
return txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive();
}