You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
source-code-hunter/docs/Spring/TX/Spring-transaction.md

1959 lines
55 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Spring 事务
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-Spring](https://github.com/SourceHot/spring-framework-read)
## 声明式事务
### Propagation
- 事务传播
```java
public enum Propagation {
/**
* 有事务则加入,没有则新建
*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
/**
* 有事务就用,如果没有就不开启(继承关系)
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
/**
* 必须在已有事务中
*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
/**
* 不管是否已有事务,都要开启新事务,老事务挂起
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
/**
* 不开启事务
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**
* 必须在没有事务的方法中调用,否则抛出异常
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),
/**
* 果已有事务,则嵌套执行,如果没有,就新建(和REQUIRED类似和REQUIRES_NEW容易混淆)
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
```
### Isolation
- 事务级别
```java
public enum Isolation {
/**
* @see java.sql.Connection
*/
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
/**
* 读未提交
*
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
*/
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
/**
* 读已提交
*
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
*/
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
/**
* 可重复读
*
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
*/
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
/**
* 可串行化
*
* @see java.sql.Connection#TRANSACTION_SERIALIZABLE
*/
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
private final int value;
Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
```
### EnableTransactionManagement
- 下面代码是一个注解方式的事务配置使用 `EnableTransactionManagement`来开启事务支持
```java
@ComponentScan(basePackages = "org.source.hot.spring.overview.ioc.tx.declarative")
@EnableTransactionManagement
public class TxConfig {
@Bean // 数据源
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("");
dataSource.setPassword("");
dataSource.setUrl("");
dataSource.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean //事务管理器
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
```
- 注解源码如下,关注于`@Import(TransactionManagementConfigurationSelector.class)`
```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
```
```java
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// 根据切面类型进行初始化
switch (adviceMode) {
case PROXY:
// 默认值
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
```
### ProxyTransactionManagementConfiguration
```java
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/**
* 事务切面
* @param transactionAttributeSource
* @param transactionInterceptor
* @return
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
// 事务切面
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 事务属性
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();
}
/***
* 事务拦截器
* @param transactionAttributeSource
* @return
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(
TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
// 事务管理器注入
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
```
### TransactionInterceptor
![image-20200729144622440](images/image-20200729144622440.png)
- 实现了`org.aopalliance.intercept.MethodInterceptor`接口的方法
```java
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
```
- 这段代码会在具有`Transactional` 的注解方法上生效
```java
@Service
public class IssueServiceImpl {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional()
public boolean insertIssue() throws Exception {
jdbcTemplate.execute("INSERT INTO `scrum`.`issue`() VALUES ()");
throw new Exception("a");
}
}
public class DeclarativeTransactionTest {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
TxConfig.class);
IssueServiceImpl bean = applicationContext.getBean(IssueServiceImpl.class);
bean.insertIssue();
System.out.println();
applicationContext.close();
}
}
```
![image-20200729145518089](images/image-20200729145518089.png)
断点开始进行查阅. 再断点后执行一步会直接进入cglib代理对象
`org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept` 具体不展开,继续往下执行
![image-20200729145637688](images/image-20200729145637688.png)
走到`invoke`方法了
入参对象查看
![image-20200729145835608](images/image-20200729145835608.png)
- 获取事务属性
```java
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method,
@Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 尝试缓存中获取
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
} else {
return cached;
}
} else {
// We need to work it out.
// 自行构建一个事务属性
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
} else {
String methodIdentification = ClassUtils
.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification
+ "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
return new MethodClassKey(method, targetClass);
}
```
![image-20200729162023837](images/image-20200729162023837.png)
- 此处方法已经获取到了这个方法就是后面的一个切面
- 确定事务管理器
```java
@Nullable
protected TransactionManager determineTransactionManager(
@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
// 空判断返回一个事务管理器
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
// 属性是否有别名
String qualifier = txAttr.getQualifier();
// 如果有
if (StringUtils.hasText(qualifier)) {
// 从 ioc 容器中根据类型和名称获取事务管理器
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
} else if (StringUtils.hasText(this.transactionManagerBeanName)) {
// 从 ioc 容器中根据类型和名称获取事务管理器
return determineQualifiedTransactionManager(this.beanFactory,
this.transactionManagerBeanName);
} else {
// 通过get方法获取
TransactionManager defaultTransactionManager = getTransactionManager();
// 如果没有
if (defaultTransactionManager == null) {
// 尝试从缓存中获取
defaultTransactionManager = this.transactionManagerCache
.get(DEFAULT_TRANSACTION_MANAGER_KEY);
// 缓存里面没有从 ioc 容器中获取并且设置缓存
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
```
![image-20200729160650401](images/image-20200729160650401.png)
- 类型转换
```java
@Nullable
private PlatformTransactionManager asPlatformTransactionManager(
@Nullable Object transactionManager) {
if (transactionManager == null
|| transactionManager instanceof PlatformTransactionManager) {
return (PlatformTransactionManager) transactionManager;
} else {
throw new IllegalStateException(
"Specified transaction manager is not a PlatformTransactionManager: "
+ transactionManager);
}
}
```
- 获取方法切面
```java
private String methodIdentification(Method method, @Nullable Class<?> targetClass,
@Nullable TransactionAttribute txAttr) {
String methodIdentification = methodIdentification(method, targetClass);
if (methodIdentification == null) {
if (txAttr instanceof DefaultTransactionAttribute) {
// 直接就获取了.方法签名.
methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor();
}
if (methodIdentification == null) {
methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
}
}
return methodIdentification;
}
```
![image-20200729161647214](images/image-20200729161647214.png)
- 创建一个新的事务根据事务传播性
```java
@SuppressWarnings("serial")
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");
}
}
}
// 处理出一个 TransactionInfo
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
```
![image-20200729163303000](images/image-20200729163303000.png)
- `tm.getTransaction`
```JAVA
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
// 获取事务的定义
TransactionDefinition def = (definition != null ? definition
: TransactionDefinition.withDefaults());
// 获取事务
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// 是否存在事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// 存在事务后处理什么操作
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
// 超时的校验. 小于默认值抛出异常
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 没有事务抛出异常
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 {
boolean newSynchronization = (getTransactionSynchronization()
!= SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
def, transaction, true, newSynchronization, debugEnabled,
suspendedResources);
doBegin(transaction, def);
prepareSynchronization(status, def);
return status;
} 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);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled,
null);
}
}
```
- `org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction`
- `org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction`
```JAVA
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 数据库链接对象
// 从事务管理器中获取数据库链接对象
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager
.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
```
- `org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend`
```JAVA
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction)
throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
// 线程名称
String name = TransactionSynchronizationManager.getCurrentTransactionName();
// 同步方法中设置
TransactionSynchronizationManager.setCurrentTransactionName(null);
// 只读设置
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
// 同步方法中设置
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
// 隔离级别
Integer isolationLevel = TransactionSynchronizationManager
.getCurrentTransactionIsolationLevel();
// 同步方法中设置
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
// 是否活跃
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
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;
}
}
```
- `prepareTransactionInfo`简单的`new`对象并且绑定线程
```JAVA
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 初始化
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// We need a transaction for this method...
if (logger.isTraceEnabled()) {
logger.trace(
"Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// The transaction manager will flag an error if an incompatible tx already exists.
txInfo.newTransactionStatus(status);
} else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled()) {
logger.trace("No need to create transaction for [" + joinpointIdentification +
"]: This method is not transactional.");
}
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
// 和线程绑定
txInfo.bindToThread();
return txInfo;
}
```
- `retVal = invocation.proceedWithInvocation();`
- 这里走的是CGLIB的方法直接会执行结果将结果返回具体方法在
`org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed`
```java
@Override
@Nullable
public Object proceed() throws Throwable {
try {
return super.proceed();
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
throw ex;
}
else {
throw new UndeclaredThrowableException(ex);
}
}
}
```
- 如果没有异常就直接处理完成返回了
- 我们现在是有异常的
```java
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 回调方法
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
// target invocation exception
// 回滚异常
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
// 消息清理
cleanupTransactionInfo(txInfo);
}
```
- `completeTransactionAfterThrowing`回滚异常的处理方法
```java
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo,
Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 做回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
} catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
} catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
} else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
// org.springframework.transaction.support.AbstractPlatformTransactionManager.commit 的方法
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
} catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
} catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
```
- 整理一下这里的流程
1. 有异常走回滚
`txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())`
2. 没有异常直接提交
`txInfo.getTransactionManager().commit(txInfo.getTransactionStatus())`
- **注意: 这里的异常如果是exception不会走回滚**
- 判断是否需要回滚
```
txInfo.transactionAttribute.rollbackOn
```
- 链路
- `org.springframework.transaction.interceptor.DelegatingTransactionAttribute#rollbackOn`
- `org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn`
```java
@Override
public boolean rollbackOn(Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace(
"Applying rules to determine whether transaction should rollback on " + ex);
}
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Winning rollback rule is: " + winner);
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
```
- `org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn`
```java
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
```
- 这就是我们的异常判断是否需要回滚
- `cleanupTransactionInfo`
数据清理
```java
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
```
```java
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
```
## 编程式事务
### DefaultTransactionDefinition
- 默认的事务定义
- 常见属性
1. timeout
2. readOnly
3. ....
### PlatformTransactionManager
```java
// 获取事务
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)throws TransactionException;
// 提交事务
void commit(TransactionStatus status) throws TransactionException;
// 回滚事务
void rollback(TransactionStatus status) throws TransactionException;
```
- 贴出一部分
![image-20200728105926218](images/image-20200728105926218.png)
- AbstractPlatformTransactionManager 定义了一些基础属性 以及一些需要子类实现的方法
```java
// 属性
defaultTimeout
nestedTransactionAllowed
validateExistingTransaction
globalRollbackOnParticipationFailure
failEarlyOnGlobalRollbackOnly
rollbackOnCommitFailure
// 方法
doGetTransaction
isExistingTransaction
useSavepointForNestedTransaction
doBegin
doSuspend
doResume
shouldCommitOnGlobalRollbackOnly
prepareForCommit
doCommit
doRollback
doSetRollbackOnly
registerAfterCompletionWithExistingTransaction
doCleanupAfterCompletion
```
### DataSourceTransactionManager
- xml配置如下
```xml
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url"
value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
```
- 两个属性,通常我们会配置datasource
```java
@Nullable
private DataSource dataSource;
private boolean enforceReadOnly = false;
```
- bean 的属性注入就不具体描述了
![image-20200728133037075](images/image-20200728133037075.png)
- `InitializingBean`
- ```java
@Override
public void afterPropertiesSet() {
if (getDataSource() == null) {
throw new IllegalArgumentException("Property 'dataSource' is required");
}
}
```
- 如果`dataSource`为空会抛出异常
- 默认单例会注册到ioc容器中.后续注册流程不具体描述
- 方法注释
```java
/**
* 获取datasource
*/
protected DataSource obtainDataSource() {
DataSource dataSource = getDataSource();
Assert.state(dataSource != null, "No DataSource set");
return dataSource;
}
/**
* 创建事务
*
* @return 事务对象
*/
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 数据库链接对象
// 从事务管理器中获取数据库链接对象
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager
.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
/**
* 是否存在事务
*
* @param transaction transaction object returned by doGetTransaction
* @return
*/
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder()
.isTransactionActive());
}
/**
* This implementation sets the isolation level but ignores the timeout. 事务的开始方法
*/
@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");
}
// 设置数据库连接
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).
// 判断是否自动提交
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);
}
// Bind the connection holder to the thread.
// 将链接和当前线程绑定
if (txObject.isNewConnectionHolder()) {
// k: datasource v: connectionHolder
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);
}
}
/**
* 挂起事务
*
* @param transaction transaction object returned by {@code doGetTransaction}
* @return 移除的链接
*/
@Override
protected Object doSuspend(Object transaction) {
// 获取事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 连接置空
txObject.setConnectionHolder(null);
// 解除资源绑定
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
/**
* 恢复事务
*
* @param transaction transaction object returned by {@code doGetTransaction}
* @param suspendedResources the object that holds suspended resources, as returned by
* doSuspend
*/
@Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
// 资源绑定
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
/**
* 做提交
*
* @param status the status representation of the transaction
*/
@Override
protected void doCommit(DefaultTransactionStatus status) {
// 事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status
.getTransaction();
// 获取链接
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
// 链接提交
con.commit();
} catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
/**
* 事务回滚
*
* @param status the status representation of the transaction
*/
@Override
protected void doRollback(DefaultTransactionStatus status) {
// 事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status
.getTransaction();
// 链接对象
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
// 回滚方法
con.rollback();
} catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
/**
* 设置回滚
*
* @param status the status representation of the transaction
*/
@Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status
.getTransaction();
if (status.isDebug()) {
logger.debug(
"Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
"] rollback-only");
}
txObject.setRollbackOnly();
}
/**
* 清除
*
* @param transaction transaction object returned by {@code doGetTransaction}
*/
@Override
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// Remove the connection holder from the thread, if exposed.
if (txObject.isNewConnectionHolder()) {
// 释放datasource绑定的资源
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// Reset connection.
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
// 重置链接
DataSourceUtils.resetConnectionAfterTransaction(
con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
} catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
/**
*
* 事务准备
*/
protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition)
throws SQLException {
if (isEnforceReadOnly() && definition.isReadOnly()) {
try (Statement stmt = con.createStatement()) {
// 执行sql 类似事务隔离级别
stmt.executeUpdate("SET TRANSACTION READ ONLY");
}
}
}
```
#### 内部类 DataSourceTransactionObject
```java
private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport {
/**
* 是否有新的链接
*/
private boolean newConnectionHolder;
/**
* 是否自动提交
*/
private boolean mustRestoreAutoCommit;
}
```
### AbstractPlatformTransactionManager
- abstract 修饰具体定义的方法不具体展开。主要关注实现`org.springframework.transaction.PlatformTransactionManager`的几个方法
#### commit 方法
```java
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
// 事务状态
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
// 处理回滚
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug(
"Global transaction is marked as rollback-only but transactional code requested commit");
}
// 处理回滚
processRollback(defStatus, true);
return;
}
// 真正的处理提交
processCommit(defStatus);
}
```
```java
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
//
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
// 前置任务是否已经执行
beforeCompletionInvoked = true;
// 嵌套事务. 是否有保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
} else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
} 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.
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
// 事务的同步状态: 回滚
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
} catch (TransactionException ex) {
// can only be caused by doCommit
// 提交失败 做回滚
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
} else {
// 事务的同步状态: 未知
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
} catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
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);
}
}
```
#### rollback 方法
```java
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
// 是否已完成
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 执行回滚
processRollback(defStatus, false);
}
```
```java
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
triggerBeforeCompletion(status);
// 嵌套事务
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 {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly()
|| isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug(
"Participating transaction failed - marking existing transaction as 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);
}
}
```
### TransactionSynchronizationManager
- 事务同步管理器
- 一些基本属性
```java
/**
* 资源
*/
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");
```
#### 资源方法
##### 获取资源
```java
public static Map<Object, Object> getResourceMap() {
// 线程变量中获取
Map<Object, Object> map = resources.get();
// 判空 如果为空给个空map如果有就返回
return (map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap());
}
```
##### 判断是否存在资源
```java
public static boolean hasResource(Object key) {
// 资源key获取
// 通过 unwrapResourceIfNecessary 会走一次资源对象转换.
// 1. InfrastructureProxy
// 2. ScopedObject
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
return (value != null);
}
```
- `unwrapResourceIfNecessary`方法会将资源具体化到接口,从接口中调用方法获取具体的资源
```java
static Object unwrapResourceIfNecessary(Object resource) {
Assert.notNull(resource, "Resource must not be null");
Object resourceRef = resource;
// unwrap infrastructure proxy
if (resourceRef instanceof InfrastructureProxy) {
resourceRef = ((InfrastructureProxy) resourceRef).getWrappedObject();
}
if (aopAvailable) {
// now unwrap scoped proxy
resourceRef = ScopedProxyUnwrapper.unwrapIfNecessary(resourceRef);
}
return resourceRef;
}
private static class ScopedProxyUnwrapper {
public static Object unwrapIfNecessary(Object resource) {
if (resource instanceof ScopedObject) {
return ((ScopedObject) resource).getTargetObject();
} else {
return resource;
}
}
}
```
- `doGetResource` 方法去获取资源
```java
@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;
}
```
##### 资源绑定
```java
public static void bindResource(Object key, Object value) throws IllegalStateException {
// 将资源转换为正真的key
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() + "]");
}
}
```
- debug 使用的是druid的数据源
![image-20200729090322058](images/image-20200729090322058.png)
- `unwrapResourceIfNecessary` 方法
```java
static Object unwrapResourceIfNecessary(Object resource) {
Assert.notNull(resource, "Resource must not be null");
Object resourceRef = resource;
// unwrap infrastructure proxy
if (resourceRef instanceof InfrastructureProxy) {
resourceRef = ((InfrastructureProxy) resourceRef).getWrappedObject();
}
if (aopAvailable) {
// now unwrap scoped proxy
resourceRef = ScopedProxyUnwrapper.unwrapIfNecessary(resourceRef);
}
return resourceRef;
}
```
显然`com.alibaba.druid.pool.DruidDataSource`不是`InfrastructureProxy`
- `aopAvailable`
```java
private static final boolean aopAvailable = ClassUtils.isPresent(
"org.springframework.aop.scope.ScopedObject",
TransactionSynchronizationUtils.class.getClassLoader());
```
```java
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (IllegalAccessError err) {
throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
className + "]: " + err.getMessage(), err);
}
catch (Throwable ex) {
// Typically ClassNotFoundException or NoClassDefFoundError...
return false;
}
}
```
看是否可以解析如果解析成功返回`true` 解析失败返回`false`
- `ScopedProxyUnwrapper.unwrapIfNecessary`
```JAVA
private static class ScopedProxyUnwrapper {
public static Object unwrapIfNecessary(Object resource) {
if (resource instanceof ScopedObject) {
return ((ScopedObject) resource).getTargetObject();
} else {
return resource;
}
}
}
```
- `com.alibaba.druid.pool.DruidDataSource`不是`ScopedObject` 直接返回
后续就是一个`map`的`put`方法不具体展开
##### 解除资源绑定
```java
public static Object unbindResource(Object key) throws IllegalStateException {
// 获取真正的资源对象
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// map 移除key
Object value = doUnbindResource(actualKey);
if (value == null) {
throw new IllegalStateException(
"No value for key [" + actualKey + "] bound to thread [" + Thread
.currentThread().getName() + "]");
}
return value;
}
@Nullable
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
// Transparently suppress a ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
value = null;
}
if (value != null && logger.isTraceEnabled()) {
logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
```
map 对象的remove操作
#### 其他
- 其他几个都是使用`ThreadLocal`进行数据设置操作即可.
---
### TransactionTemplate
- 属性
```java
@Nullable
private PlatformTransactionManager transactionManager;
```
前文说到 `DataSourceTransactionManager` 实现了 `PlatformTransactionManager` 因此配置的时候我们有如下片段
```xml
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
```
- 事务操作模板类图
![image-20200728094658684](images/image-20200728094658684.png)
- `org.springframework.beans.factory.InitializingBean`接口的实现
```java
@Override
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
```
#### execute
```java
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
// 事务管理是否是 xxx接口
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
// 强转执行
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager)
.execute(this, action);
} else {
// 获取事务状态
TransactionStatus status = this.transactionManager.getTransaction(this);
// 返回结果
T result;
try {
// 事务回调执行
result = action.doInTransaction(status);
} catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
// 回滚异常
rollbackOnException(status, ex);
throw ex;
} catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
// 回滚异常
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex,
"TransactionCallback threw undeclared checked exception");
}
// 提交
this.transactionManager.commit(status);
return result;
}
}
```