事务
- Spring事务
- 定义数据源
- 定义事务管理平台
- 事务的传播属性
- 注解开启事务
- 1. ProxyTransactionManagementConfiguration
- 2. TransactionInterceptor
- 3. ReflectiveMethodInvocation#proceed()
- 4. TransactionAspectSupport#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation)
- 5. TransactionAspectSupport#determineTransactionManager(@Nullable TransactionAttribute txAttr)
- 6. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(), TransactionAspectSupport#createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification)
- 7. AbstractPlatformTransactionManager#getTransaction(@Nullable TransactionDefinition definition)
- 8. DataSourceTransactionManager#doGetTransaction()
- 9. 回到第7步 AbstractPlatformTransactionManager#getTransaction(),DataSourceTransactionManager#doBegin(Object transaction, TransactionDefinition definition)
- 10. 回到第7步 AbstractPlatformTransactionManager#getTransaction(),AbstractPlatformTransactionManager#handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)
- 11. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(),TransactionAspectSupport#completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex)
- 12. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(),TransactionAspectSupport#commitTransactionAfterReturning(@Nullable TransactionInfo txInfo)
- 案例分析
Spring事务
- Spring 中事务是用 AOP 切面技术来实现的。
- 首先用注解的方式引入事务管理功能,代码如下
- 引用这个注解就添加了注解事务功能,但是我们自己还是需要定义数据源和事务管理平台
- 数据源和事务管理平台的加载都是在类 ProxyTransactionManagementConfiguration 进行的
- 事务对应连接(connection),连接对应用户会话(session)
定义数据源
package org.example.dataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Component
public class DataSourceConfiguration {
@Resource
Environment environment;
@Bean
public DataSource comboPooledDataSource() {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
try {
comboPooledDataSource.setDriverClass(environment.getProperty("jdbc.driverClassName"));
comboPooledDataSource.setJdbcUrl(environment.getProperty("jdbc.url"));
comboPooledDataSource.setUser(environment.getProperty("jdbc.username"));
comboPooledDataSource.setPassword(environment.getProperty("jdbc.password"));
comboPooledDataSource.setMinPoolSize(10);
comboPooledDataSource.setMaxPoolSize(100);
comboPooledDataSource.setMaxIdleTime(1800);
comboPooledDataSource.setAcquireIncrement(3);
comboPooledDataSource.setMaxStatements(1000);
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setIdleConnectionTestPeriod(60);
comboPooledDataSource.setAcquireRetryAttempts(30);
comboPooledDataSource.setBreakAfterAcquireFailure(false);
comboPooledDataSource.setTestConnectionOnCheckout(false);
comboPooledDataSource.setAcquireRetryDelay(100);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return comboPooledDataSource;
}
}
定义事务管理平台
@Bean
public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dtm = new DataSourceTransactionManager();
dtm.setDataSource(dataSource);
return dtm;
}
事务的传播属性
-
用来控制事务传输的策略,在一个请求内的事务回滚和提交;对比隔离级别则是不同请求的事务控制。
-
PROPAGATION_REQUIRED
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 -
PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。 -
PROPAGATION_MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常。 -
PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。 -
PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 -
PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。 -
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
注解开启事务
- ConfigurationClassPostProcessor类支持了@ComponentScan、@Configuration、@Import、@ImportSource等注解,这个selectImports()方法在 ConfigurationClassParser类的569行调用
- 这里把AutoProxyRegistrar和ProxyTransactionManagementConfiguration封装成beanDefinition对象
1. ProxyTransactionManagementConfiguration
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/*
* 创建事务切面实例
* BeanFactoryTransactionAttributeSourceAdvisor
*
* */
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//transactionAttributeSource()搜集@Transactional注解上设置的所有属性包装成对象,设置到advisor中
advisor.setTransactionAttributeSource(transactionAttributeSource());
//设置通知类
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/*
* 创建事务advice
* TransactionInterceptor
* */
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
//这个TransactionInterceptor实现了MethodeInterceptor接口,到aop链式调用时,会调到里面的invoke()方法
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
//事务管理器要跟数据源挂钩,所以需要自己定义
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
2. TransactionInterceptor
- 实现了MethodInterceptor,一定会有invoke()方法
3. ReflectiveMethodInvocation#proceed()
- aop中,执行链式调用的代码
4. TransactionAspectSupport#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation)
- 当程序运行带有@Transactional注解的方法时,就会调用到实现了MethodInterceptor接口的类的invoke()方法,最后会执行到这里,是事务的核心方法
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 1.获取事务属性类 AnnotationTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
// 2.获取方法上面有@Transactional注解的属性,包装成TransactionAttribute对象
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 3.获取事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 4.获取添加了@Transactional的方法名
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 5.开启事务,根据不同的
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 6.火炬传递,会调用到被代理方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 7.事务回滚,rollback()
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 8.如果存在挂起的链接对象,重新绑定线程与连接对象的关系
cleanupTransactionInfo(txInfo);
}
// 9.事务提交,commit()
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 下面是编程式事务的处理方法,只有你自定义了一个CallbackPreferringPlatformTransactionManager类型的编程式事务才会走下面
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
5. TransactionAspectSupport#determineTransactionManager(@Nullable TransactionAttribute txAttr)
- 获取事务管理器
- 如果事务管理为空,先到缓存中找,如果缓存没有,再到beanFactory中找PlatformTransactionManager类的类,最后放到缓存中
6. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(), TransactionAspectSupport#createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification)
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
//开启事务,这里重点看
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
//创建事务信息对象,记录新老事务信息对象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
7. AbstractPlatformTransactionManager#getTransaction(@Nullable TransactionDefinition definition)
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 1.拿到DataSourceTransactionObject对象
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 2.第一次进来connectionHolder为空的,所以不存在事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 3.第一次进来大部分会走这里
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 4.先挂起
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 5.创建事务状态对象,其实就是封装了事务对象的一些信息,记录事务状态的
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 6.开启事务,重点看看 DataSourceTransactionObject
doBegin(transaction, definition);
// 7.开启事务后,改变事务状态
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
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);
}
}
8. DataSourceTransactionManager#doGetTransaction()
- DataSourceTransactionObject 为事务对象,用来管理连接对象Connection
protected Object doGetTransaction() {
// 1.管理connection对象,创建回滚点,按照回滚点回滚,释放回滚点
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// 2.DataSourceTransactionManager默认是允许嵌套事务的
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 3.obtainDataSource() 获取数据源对象,其实就是数据库连接块对象
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
- 从ThreadLocal中拿到连接对象,方便在嵌套事务中,拿到同一个连接
9. 回到第7步 AbstractPlatformTransactionManager#getTransaction(),DataSourceTransactionManager#doBegin(Object transaction, TransactionDefinition definition)
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 1.如果没有数据库连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 2.从连接池里面获取连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 3.把连接包装成ConnectionHolder,然后设置到事务对象中
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 4.从数据库连接中获取隔离级别
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");
}
// 5.关闭连接的自动提交,其实这步就是开启了事务
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()) {
// 6.如果是新创建的事务,则建立当前线程和数据库连接的关系
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);
}
}
- 建立连接池和连接对象的映射关系
- 建立用户线程和map的映射关系,后面通过用户线程可以拿到一个唯一的连接
- 开启事务最主要的操作就是关闭自动提交
10. 回到第7步 AbstractPlatformTransactionManager#getTransaction(),AbstractPlatformTransactionManager#handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)
- 如果是一个线程运行了第二个带有@Transactional注解的方法就走到handleExistingTransaction()方法
- 第二次进来connectionHolder不为空,进入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);
//修改事务状态信息,把事务的一些信息存储到当前线程中,ThreadLocal中
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 1.新建事务,如果当前存在事务,把当前事务挂起
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 2.挂起,解除旧的连接对象与线程的绑定关系,并把旧的连接对象包装到SuspendedResourcesHolder中
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 事务状态设置为true,表示是一个新的事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 3.开启事务(这是一个新的事务)
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 4.如果当前存在事务,则在嵌套事务内执行,嵌套事务没有做挂起操作,所以用的是同一个连接对象connection
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.
// 事务状态设置为false
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 5.在执行被代理方法前,创建回滚点
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);
// 4.如果传播属性是PROPAGATION_REQUIRED,上面的if,else都不会进,直接返回下面这个结果
// 特别要注意的是这里把事务的状态设置为了false,但是第一次进来的时候,事务状态被设置为了true
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
- 第一次进getTransaction()得到的事务状态,true(表示是新的事务)
- 如果传播属性是PROPAGATION_REQUIRED,则第二次进getTransaction()得到的事务状态,false(说明不是新的事务)
- 如果传播属性是PROPAGATION_REQUIRES_NEW,则第二次进getTransaction()得到的事务状态,true(说明是新的事务)
- PROPAGATION_REQUIRED连接对象是同一个,事务对象DataSourceTransactionObject 不是同一个。
- PROPAGATION_REQUIRES_NEW连接对象也不是同一个(把旧的挂起了),事务对象DataSourceTransactionObject 也不是同一个。
- 事务对象DataSourceTransactionObject 每次都会new一个新的。
11. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(),TransactionAspectSupport#completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex)
- 事务回滚
- 把事务状态属性对象传进来
- 只有事务状态是true的才会进入if,走事务回滚方法doRollback(status)
12. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(),TransactionAspectSupport#commitTransactionAfterReturning(@Nullable TransactionInfo txInfo)
- 事务提交
- 把事务对象的状态属性对象传进来
- 走到此方法最后一行代码
- 嵌套事务情况,存在回滚点,则进入if,然后删除回滚点
- 如果是进入第一个加了@Transactional的方法,且传播属性是PROPAGATION_REQUIRED时,要么不存在回滚点,或者嵌套事务的回滚点都被删除了,肯定会走下面代码,判断事务状态,如果是true(表示是新的事务),进入if,会走到事务提交方法doCommit(status),把所有的事务都提交
- 由此可见,只有事务状态是true的事务才能提交
案例分析
1. 场景一
- 3个方法的事务传播属性都是REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void transation() {
transationService.getTicket();
transationService.getTicketModeOne();
}
@Transactional
public int getTicket() {
return 0;
}
@Transactional
public int getMoney() {
return 0;
}
- 模拟事务关系
public void transation() {
try{
try{
getTicket();
}catch (Exception e){
ticketRollBack();
throw e;
}
ticketCommit();
try{
getMoney();
}catch (Exception e){
moneyRollBack();
throw e;
}
moneyCommit();
}catch (Exception e){
transationRollBack();
throw e;
}
transationCommit();
}
- 如果getTicket()方法发生异常,则进入catch,因为传播属性是REQUIRED,所以getTicket方法的事务状态是false,不会走ticketRollBack()方法回滚;因此抛出异常,被transation方法的cathc捕获,而且transation方法的事务状态是true,所以会走transationRollBack()回滚;
- 如果是getMoney()方法发生异常,和前面的结果是一样的,走transationRollBack()回滚;
- 最终结果是,getTicket()和getMoney()都不会改变数据库内的数据。
2. 场景二
- getTicket方法的事务传播属性是REQUIRES_NEW,其他为REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void transation() {
transationService.getTicket();
transationService.getTicketModeOne();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int getTicket() {
return 0;
}
@Transactional
public int getMoney() {
return 0;
}
- 模拟事务关系
public void transation() {
try{
try{
getTicket();
}catch (Exception e){
ticketRollBack();
throw e;
}
ticketCommit();
try{
getMoney();
}catch (Exception e){
moneyRollBack();
throw e;
}
moneyCommit();
}catch (Exception e){
transationRollBack();
throw e;
}
transationCommit();
}
- 如果getTicket()方法发生异常,则进入catch,因为传播属性是REQUIRES_NEW,所以getTicket方法的事务状态是true,会走ticketRollBack方法进行回滚;走到外层catch,但是transationRollBack方法不会回滚,但是getMoney方法也没有执行,所以最终结果是,getTicket和getMoney都不会改变数据库内的数据;
- 如果是getMoney()方法发生异常,则getTicket()会正常执行,而且会走ticketCommit()提交事务,因为getTicket的事务状态是true,而getMoney方法的异常,最终会被最外层的catch捕获,走transationRollBack方法回滚,所以最终结果是,getTicket方法改变了数据库内的数据,而getMoney方法没有改变数据库内的数据
3. 场景三
- getTicket和getMoney方法的事务传播属性是REQUIRES_NEW,transation为REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void transation() {
transationService.getTicket();
transationService.getTicketModeOne();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int getTicket() {
return 0;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int getMoney() {
return 0;
}
- 模拟事务关系
public void transation() {
try{
try{
getTicket();
}catch (Exception e){
ticketRollBack();
throw e;
}
ticketCommit();
try{
getMoney();
}catch (Exception e){
moneyRollBack();
throw e;
}
moneyCommit();
}catch (Exception e){
transationRollBack();
throw e;
}
transationCommit();
}
- 如果getTicket()方法发生异常,则进入catch,走ticketRollBack回滚,再到最外层catch,getMoney方法没有执行,最终结果是getTicket和getMoney都没改变数据;
- 如果是getMoney发生异常,则getTicket改变了数据,但是getMoney没有改变数据。
- 注意: 以上的异常都是被spring捕获的,如果你自己在业务方法内加了try-catch,发生的异常被方法本身吞掉了,spring是捕获不到异常的,也就不会走到回滚方法
4. 场景四
- getTicket和getMoney方法的事务传播属性是PROPAGATION_NESTED(可以按照回滚点回滚),transation为REQUIRED,希望getTicket或getMoney发生异常,各自按照回滚点回滚,而不影响其他方法对数据的改变
@Transactional(propagation = Propagation.REQUIRED)
public void transation() {
transationService.getTicket();
transationService.getTicketModeOne();
}
@Transactional(propagation = Propagation.PROPAGATION_NESTED)
public int getTicket() {
return 0;
}
@Transactional(propagation = Propagation.PROPAGATION_NESTED)
public int getMoney() {
return 0;
}
- 模拟事务关系
public void transation() {
try{
try{
getTicket();
}catch (Exception e){
ticketRollBack();
throw e;
}
ticketCommit();
try{
getMoney();
}catch (Exception e){
moneyRollBack();
throw e;
}
moneyCommit();
}catch (Exception e){
transationRollBack();
throw e;
}
transationCommit();
}
- getTicket()正常执行,ticketCommit()删除回滚点,但是getMoney()方法发生异常,则进入catch,走moneyRollBack按照回滚点回滚,再到最外层catch,走transationRollBack方法全部回滚,最终结果是getTicket和getMoney都没改变数据,与各自按照回滚点回滚,而不影响其他方法对数据的改变的目标不一致
- 解决方法:在transation方法内部加try-catch,把内部异常吞掉,不被transation方法的spring的catch捕获到,就不会全部回滚
@Transactional(propagation = Propagation.REQUIRED)
public void transation() {
try {
transationService.getTicket();
transationService.getMoney();
} catch (Exception e) {
e.printStackTrace();
}
}