一、简介
1.1、简介
摘自spring官网Data Access (spring.io)
1.1.3. Spring Framework’s Consistent Programming Mode
Spring解决了全局和本地事务的缺点。它允许应用程序开发人员在任何环境中使用一致的编程模型。您只需编写一次代码,就可以从不同环境中的不同事务管理策略中受益。Spring框架提供声明式和编程式事务管理。大多数用户更喜欢声明式事务管理,我们在大多数情况下都建议这样做。
通过编程事务管理,开发人员可以使用Spring框架事务抽象,它可以运行在任何底层事务基础设施上。使用首选的声明式模型,开发人员通常很少或不编写与事务管理相关的代码,因此不依赖于Spring Framework事务API或任何其他事务API。
spring-tx对用户提供统一的声明式事务、编程式事务解决方案,对事务的入口,定义、传播、提交、回滚进行了封装,与业务代码隔离,抽象出事务操作PlatformTransactionManager顶级接口,通过将连接及其他需要同步的资源交由事务同步管理器(TransactionSynchronizationManager->ThreadLocal)管理。应用框架、业务程序,只需要通过TransactionSynchronizationManager获取同步资源,操作数据库,不需要或很少关注事务的相关操作,这些操作由spring-tx接管。
spring-tx在AbstractPlatformTransactionManager中抽象出了getTransaction(开启事务)、commit(提交事务)、rollback(回滚事务)供用户实现,各需要接入spring-tx的框架、应用程序可通过继承该类实现commit、rollback、doBegin、doSuspend、doResume、doCommit、doRollback.......定制化需求,结合TransactionSynchronizationManager,DataSourceUtils以实现与spring-tx的整合,将事务管理交由spring-tx。
spring-tx定义了一套事物编程方式。用户在使用时只需要通过@Transaction标明方法,或者通过PlatformTransactionManager使用编程式事务。
1.2、使用
1.2.1、声明式事务
public class TransactionalService {
@Transactional("order")
public void setSomething(String name) { ...
// 注册事务相关回调回调
TransactionSynchronizationManager.registerSynchronization(new DemoTransactionSynchronization());
}
@Transactional("account")
public void doSomething() { ... }
@Transactional("reactive-account")
public Mono<Void> doSomethingReactive() { ... }
}
1.2.2、使用spring的事务监听器
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import javax.annotation.Resource;
@Service
public class TransactionCallBackDemo {
@Resource
private ApplicationEventPublisher applicationEventPublisher;
@Transactional
public void something() {
// .......
applicationEventPublisher.publishEvent(new MyTransactionEvent(new Object()));
}
// 定事件
public class MyTransactionEvent extends ApplicationEvent {
public MyTransactionEvent(Object event) {
super(event);
}
}
@Component
public class MyEventListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void onHelloEvent(MyTransactionEvent event) {
// something ........
}
}
}
1.2.3、编程式事务
// 可阅读或使用 org.springframework.transaction.support.TransactionTemplate#execute
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class TransactionalService {
PlatformTransactionManager transactionManager;
public void doSoming() {
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
// 设置事务传播方式
defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 开启事务
TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
try{
// 业务逻辑................
// 注册事务相关回调回调
TransactionSynchronizationManager.registerSynchronization(new DemoTransactionSynchronization());
transactionManager.commit(transactionStatus);
}catch (Exception | Error e){
transactionManager.rollback(transactionStatus);
}
}
static class DemoTransactionSynchronization extends TransactionSynchronizationAdapter {
public DemoTransactionSynchronization() {
super();
}
@Override
public int getOrder() {
return super.getOrder();
}
@Override
public void suspend() {
// super.suspend();
// doSomthing
}
@Override
public void resume() {
// doSomthing
}
@Override
public void flush() {
// doSomthing
}
/**
* 在事务提交之前调用(在“beforeComplement”之前)。
* 例如,可以将事务性OR映射会话刷新到数据库。此回调并不意味着事务将被实际提交
* 。在调用此方法之后,仍然可以进行回滚决策。这个回调是为了执行只有在提交仍有机会发生时才相关的工作,
* 例如将SQL语句刷新到数据库。请注意,异常将传播到提交调用程序,并导致事务回滚。
* @param readOnly whether the transaction is defined as read-only transaction
*/
@Override
public void beforeCommit(boolean readOnly) {
// doSomthing
}
/**
* 在事务commit/rollback之前调用。可以在事务完成前执行资源清理。
* 此方法将在beforeCommit之后调用,即使在beforeCommit引发异常时也是如此。
* 此回调允许在事务完成之前关闭资源,以获得任何结果。
*/
@Override
public void beforeCompletion() {
// doSomthing
}
/**
* 事务提交成功后执行回调。可以在成功提交主事务之后立即执行进一步的操作。
* 例如,可以提交主交易成功提交后的进一步操作,如确认消息或电子邮件。
* 注意:事务将已经提交,但事务资源可能仍然处于活动状态并且可以访问。
* 因此,此时触发的任何数据访问代码仍将“参与”原始事务,允许执行一些清理(不再有提交!)
* ,除非它明确声明需要在单独的事务中运行。因此:对于从这里调用的任何事务性操作,
* 请使用PROPAGATION_REQUIRES_NEW。
*/
@Override
public void afterCommit() {
// doSomthing
}
@Override
public void afterCompletion(int status) {
switch (status){
case STATUS_COMMITTED:
// 已提交
break;
case STATUS_ROLLED_BACK:
// 已回滚
break;
case STATUS_UNKNOWN:
// 事务未知状态
break;
}
// 在事务commit/rollback之后调用。可以在事务完成后执行资源清理。
// 事务将已经提交或回滚,但事务资源可能仍然处于活动状态并且可以访问。
// 因此,此时触发的任何数据访问代码仍将“参与”原始事务,允许执行一些清理(不再有提交!),
// 除非它明确声明需要在单独的事务中运行。因此:对于从这里调用的任何事务性操作,
// 请使用PROPAGATION_REQUIRES_NEW。
}
}
}
二、核心类
2.1、部分内部核心类
2.1.1、TransactionSynchronization
摘自翻译
事务同步回调的接口。由AbstractPlatformTransactionManager支持。TransactionSynchronization实现可以实现Ordered接口来影响其执行顺序。未实现Ordered接口的同步将附加到同步链的末尾。
2.1.2、TransactionStatus
摘自翻译
表示事务的状态。事务代码可以使用它来检索状态信息,并以编程方式请求回滚(而不是引发导致隐式回滚的异常)。
AbstractPlatformTransactionManager使用的org.springframework.transaction.TransactionStatus接口的默认实现。基于底层“事务对象”的概念。保存AbstractPlatformTransactionManager内部需要的所有状态信息,包括由具体事务管理器实现确定的通用事务对象。支持将与保存点相关的方法委派给实现SavepointManager接口的事务对象。
默认实现org.springframework.transaction.support.DefaultTransactionStatus、SimpleTransactionStatus,通常是用DefaultTransactionStatus。
2.1.3、TransactionDefinition
==org.springframework.transaction.annotation.Transactional#propagation
摘自翻译
定义Spring兼容事务属性的接口。基于类似于EJB CMT属性的传播行为定义。请注意,除非启动实际的新事务,否则不会应用隔离级别和超时设置。由于只有PROPAGATION_REQUIRED、PROPAGATION_QUIRES_NEW和PROPAGATION _NESTED会导致这种情况,因此在其他情况下指定这些设置通常没有意义。此外,请注意,并非所有事务管理器都支持这些高级功能,因此在给定非默认值时可能会引发相应的异常。
事务传播属性
PROPAGATION_REQUIRED | 支持当前事务;当前不存在,创建新事务 |
PROPAGATION_SUPPORTS | 支持当前事务;当前不存在,以非事务方式运行 |
PROPAGATION_MANDATORY | 支持当前事务;当前不存在,抛出异常 |
PROPAGATION_REQUIRES_NEW | 创建一个新事务,如果当前事务存在,则挂起该事务 |
PROPAGATION_NOT_SUPPORTED | 不支持当前事务,以非事务方式运行 |
PROPAGATION_NEVER | 不支持当前事务;如果存在当前事务,则引发异常,事务同步在PROPAGATION_NEVER范围内不可用。 |
PROPAGATION_NESTED | 如果存在当前事务,则在嵌套事务中执行,当前不存在,创建新事务 |
超时属性
==org.springframework.transaction.annotation.Transactional#timeout
默认使用底层数据库超时时间
数据库隔离级别
默认数据库的隔离级别
==org.springframework.transaction.annotation.Transactional#isolation
2.1.4、TransactionSynchronizationManager
事务同步管理器
摘自翻译
管理每个线程的资源和事务同步的中心委托。由资源管理代码使用,但不由典型的应用程序代码使用。
支持每个键一个资源而不覆盖,也就是说,在为同一个键设置新的资源之前,需要删除一个资源。如果同步处于活动状态,则支持事务同步列表。
资源管理代码应该通过getResource检查线程绑定资源,例如JDBC连接或Hibernate会话。这样的代码通常不应该将资源绑定到线程,因为这是事务管理器的职责。另一种选择是,如果事务同步处于活动状态,则在首次使用时延迟绑定,以执行跨越任意数量资源的事务。
事务同步必须由事务管理器通过initSynchronization()和clearSynchronization()激活和停用。
这由AbstractPlatformTransactionManager自动支持,因此也由所有标准Spring事务管理器自动支持,如org.springframework.transaction.jta.JtaTransactionManager和org.springfframework.jdbc.datasource.DataSourceTransactionManager。
资源管理代码应该只在该管理器处于活动状态时注册同步,这可以通过isSynchronizationActive进行检查;否则它应该立即执行资源清理。如果事务同步未处于活动状态,则表示没有当前事务,或者事务管理器不支持事务同步。
例如,同步用于在JTA事务中始终返回相同的资源,例如,任何给定DataSource或SessionFactory的JDBC连接或Hibernate会话。
2.2.5、AbstractPlatformTransactionManager
摘自翻译
实现Spring标准事务工作流的抽象基类,作为具体平台事务管理器(如org.springframework.transaction.jta.JtaTransactionManager)的基础。
该基类提供以下工作流处理:
1.确定是否存在现有事务;
2.应用适当的传播行为;
3.必要时暂停和恢复交易;
4.在提交时检查仅回滚标志;
5.对回滚应用适当的修改(仅限实际回滚或设置回滚);
6.触发已注册的同步回调(如果事务同步处于活动状态)。
子类必须为事务的特定状态实现特定的模板方法,例如:开始、挂起、恢复、提交、回滚。其中最重要的是抽象的,必须通过具体的实施来提供;对于其余部分,提供了默认值,因此重写是可选的。
事务同步是一种注册回调的通用机制
2.2.6、DataSourceUtils
摘自翻译
提供用于从DataSource获取JDBC连接的静态方法的Helper类。包括对Spring托管事务连接的特殊支持,例如由DataSourceTransactionManager或org.springframework.transaction.jta.JtaTransactionManager管理。由Spring的org.springfframework.jdbc.core.JdbcTemplate、Spring的jdbc操作对象和jdbc DataSourceTransactionManager内部使用。也可以直接在应用程序代码中使用。
2.2、外部核心类
2.2.1、spring-boot自动装配相关类
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration
2.2.2、AOP相关类
org.springframework.transaction.annotation.EnableTransactionManagement
org.springframework.transaction.annotation.TransactionManagementConfigurationSelector
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
org.springframework.transaction.interceptor.TransactionInterceptor
org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
org.springframework.transaction.annotation.EnableTransactionManagement
org.springframework.transaction.annotation.TransactionManagementConfigurationSelector
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
摘自翻译:
org.springframework.transaction.interceptor.TransactionAttributeSource接口的实现,用于处理JDK1.5+注释格式的事务元数据。
这个类读取Spring的JDK 1.5+Transactional注释,并向Spring的事务基础结构公开相应的事务属性。还支持JTA 1.2的javax.transaction.Transactional和EJB3的javax.ejb.TransactionAttribute注释(如果存在)。此类也可以作为自定义TransactionAttributeSource的基类,或者通过TransactionAnnotationParser策略进行自定义。
org.springframework.transaction.interceptor.TransactionInterceptor
摘自翻译:
AOP联盟MethodInterceptor,用于使用公共Spring事务基础设施(PlatformTransactionManager)进行声明性事务管理。
派生自TransactionAspectSupport类,该类包含与Spring的底层事务API的集成。TransactionInterceptor只是按照正确的顺序调用相关的超类方法,如invokeWithinTransaction。
org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
BeanFactoryTransactionAttributeSourceAdvisor(Advisor)
1、TransactionAttributeSourcePointcut#match(AOP匹配)
通过AnnotationTransactionAttributeSource#getTransactionAttribute解析事务属性,以返回的事务属性TransactionAttribute是否为空确定是否对方法进行代理。
AnnotationTransactionAttributeSource#getTransactionAttribute方法委托适配TransactionAnnotationParser的实现类对事务进行解析,目前spring适配兼容了 jta,spring,Ejb3三种
2、TransactionInterceptor(advice)
对1中拦截的复合条件的方法进行增强、委托PlatformTransactionManager对事务进行接管实现与业务代码节藕,允许应用程序开发人员在任何环境中使用一致的编程模型。您只需编写一次代码,就可以从不同环境中的不同事务管理策略中受益。Spring框架提供声明式和编程式事务管理
三、部分核心代码
org.springframework.jdbc.datasource.DataSourceTransactionManager类结构图
引用前面的代码
// 可阅读或使用 org.springframework.transaction.support.TransactionTemplate#execute
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class TransactionalService {
PlatformTransactionManager transactionManager;
public void doSoming() {
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
// 设置事务传播方式
defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 1.开启事务
TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
try{
// 业务逻辑................
// 2.注册事务相关回调回调
TransactionSynchronizationManager.registerSynchronization(new DemoTransactionSynchronization());
// 3.提交事务
transactionManager.commit(transactionStatus);
}catch (Exception | Error e){
// 4.回滚事务
transactionManager.rollback(transactionStatus);
}
}
}
1、开启事务org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
boolean debugEnabled = logger.isDebugEnabled();
// 调用模板方法,获取自定义事务对象
Object transaction = doGetTransaction();
// 当前是否存在事务
if (isExistingTransaction(transaction)) {
// 当前存在事务走事务传播策略
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 检查是否超时
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 检查事务传播属性
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 暂停事务
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
// 开启事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
// 恢复暂停事务,相当于不做任何处理
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
// 创建一个空事务:无实际事务,但是会用于事务的传播、同步判断
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 为给定的参数创建一个新的TransactionStatus,并根据需要初始化事务同步。
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
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");
}
// 暂停事务,返回 suspendedResources 暂停事务状态信息
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 创建一个新的TransactionStatus用于存储上被暂停事务的suspendedResources信息,
// 返回TransactionStatus用于下一事务传播节点
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() + "]");
}
// 暂停事务,返回 suspendedResources 暂停事务状态信息
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 开启一个新事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 嵌套事务执行
// 方法A(PROPAGATION_REQUIRES_NEW)方法B(PROPAGATION_NESTED) A->B A事务是否提交不受B异常影响,B是否提交受A是否异常影响
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);
// 创建 savepoint B回滚是回滚到此节点,A可继续操作
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.
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// 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);
}
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
根据给定的事务定义,使用语义开始新的事务。不必关心应用传播行为,因为这已经由这个抽象管理器处理了。当事务管理器决定实际启动一个新事务时,就会调用此方法。要么之前没有任何交易,要么之前的交易已经暂停。一个特殊的场景是没有保存点的嵌套事务:如果useSavepointForNestedTransaction()返回“false”,则在必要时将调用此方法来启动嵌套事务。在这种情况下,将有一个活动事务:该方法的实现必须检测到这一点并启动适当的嵌套事务
protected void doBegin(Object transaction, TransactionDefinition definition) {
// doGetTransaction 获取的
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");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 设置初始化信息
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
// 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).
// 如有必要,请切换到手动提交。在一些JDBC驱动程序中,这是非常昂贵的,所以我们不想做不必要的事情(例如,如果我们已经明确配置了连接池来设置它)
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 如果只读,设置连接为只读
prepareTransactionalConnection(con, definition);
// 设置事务状态
txObject.getConnectionHolder().setTransactionActive(true);
// 设置超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 将连接绑定到线程
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);
}
}
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();
}
}
2、注册回调
3、提交事务
org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
// 提交前预处理
prepareForCommit(status);
// 触发事务提交前回调
triggerBeforeCommit(status);
// 触发事务完成前回电
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
// 事务在事务传播过程中保存过 savePoint 释放
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
// 是后新建事务,在事务传播过程中,根据不同的传播策略,新建不同的TransactionStatus
// 不同的TransactionStatus执行不同的提交回滚策略
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
// 是否被标记为RollbackOnly
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
// 如果我们有一个仅全局回滚的标记,但仍然没有从提交中获得相应的异常,则抛出UnexpectedRollbackException。
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
// 被标记为全局回滚异常
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
// 触发org.springframework.transaction.support.TransactionSynchronization.afterCompletion回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
// 事务异常
catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
// 触发org.springframework.transaction.support.TransactionSynchronization.afterCompletion回调
doRollbackOnCommitException(status, ex);
}
else {
// 触发org.springframework.transaction.support.TransactionSynchronization.afterCompletion回调
// TransactionSynchronization.STATUS_UNKNOWN
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
// 未知异常
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
// 触发org.springframework.transaction.support.TransactionSynchronization.beforeCompletion
triggerBeforeCompletion(status);
}
// 触发org.springframework.transaction.support.TransactionSynchronization.afterCompletion回调
doRollbackOnCommitException(status, ex);
throw ex;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
// 归还资源,同步上一被暂停的事务
cleanupAfterCompletion(status);
}
}
4、回滚事务
org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
// 触发回调
triggerBeforeCompletion(status);
// 存在Savepoint 回滚到Savepoint
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
//新事务回滚
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
// 委托模板方法回滚事务
doRollback(status);
}
else {
// 纯在事务
if (status.hasTransaction()) {
// 是否被标记
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
// 标记当前事务为rollback-only
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 触发回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
// 归还资源,同步被暂停的事务
cleanupAfterCompletion(status);
}
}
四、事务传播解读
MethodA调用MethodB MethodA(默认)和MethodB(PROPAGATION_REQUIRES_NEW)分别使用不同的事务传播策略
MethodA执行:
当前不存在事务,根据传播策略,
1、MethodA开启事务,同步连接信息到线程(TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder()))以及当前运行事务状态信息。
2、返回DefaultTransactionStatus。
MethodB执行:
当前存在事务,根据传播策略是否暂停当前事务,MethodB传播方式为PROPAGATION_REQUIRES_NEW,
1、挂起当前事务,将当前事务状态信息,连接信息,封装成SuspendedResourcesHolder对象
2、新建DefaultTransactionStatus,将封装的SuspendedResourcesHolder联同newTransaction=true作为构造参数传入 ;
3、开启新事务,同步新开事务的连接信息以及开启事务的状态相关信息,返回DefaultTransactionStatus
此时通过DatasourceUtils或TransactionSynchronizationManager获取的连接,或状态信息为MethodB新开事务信息
MethodB提交事务:
没有savePoint,触发相关回调,是新事务,提交事务,触发相关回调,归还释放相关资源,根据SuspendedResourcesHolder同步被暂停的事务状态信息以及连接信息;
此时通过DatasourceUtils或TransactionSynchronizationManager获取的连接,或状态信息为被恢复MethodA的事务信息
MethodA 提交事务:
释放资源,清空当前事务状态信息
五、mybatis整合
mybatis对外提供事务的对接接口org.apache.ibatis.transaction.Transaction从中获取连接,提交回滚事务,org.mybatis.spring.transaction.SpringManagedTransaction该类实现了该接口
获取连接是通过spring-tx提供的工具类org.springframework.jdbc.datasource.DataSourceUtils,从事务同步管理器org.springframework.transaction.support.TransactionSynchronizationManager中获取。
这样mybatis就只需要关注使用获取到的连接操作DB,不需要关注事务的传播,事务的编程方式,关于事务的操作就全部托管给Spring-tx管理。