1. spring 事务管理接口
spring 使用 PlatformTransactionManager
接口管理事务
public interface PlatformTransactionManager {
TransactionStatus getTransaction(
TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
具体到 mybatis, 使用 org.springframework.jdbc.datasource.DataSourceTransactionManager
作为事务管理器. spring-boot-autoconfigure 会自动配置这个类
2. 事务是如何注解到方法上的
方法上的事务之所以生效, 是因为 transactional metadata 使用 spring AOP 产生了一个代理对象. 该对象用 TransactionInterceptor
结合一个具体的 PlatformTransactionManager
实现类, 来包围方法调用.
spring-boot 使用事务处理时, 加入的 @EnableTransactionManagement
注解, 会引入 @Configuration
配置类 ProxyTransactionManagementConfiguration
, 该类定义了 BeanFactoryTransactionAttributeSourceAdvisor
包含切点 pointCut 和 增强 advice
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
... ...
return advisor;
}
@Bean
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
事务传播属性
- 什么时候需要事务传播?
一个带@Transactional
的 service 方法, 调用了另一个@Transactional
的 service 方法, 此时如何处理内层和外层事务 - 有哪些传播选项?
选项在public enum Propagation{}
枚举中定义
(1)PROPAGATION_REQUIRED(默认)
: 如果外层方法有事务, 则使用外层事务; 否则自己新建一个事务
(2)PROPAGATION_REQUIRES_NEW
: 内层调用都要创建自己的事务. 如果外层调用已存在事务, 则先挂起外层事务. 因此内外层事务是相互独立的, 无论内层调用还是外层调用, 一方的回滚不会造成另一方的回滚
(3)PROPAGATION_NESTED
: 内层调用和外层调用使用同一个物理事务(如果外层不存在事务,则自己创建一个事务), 在其上加上各种 savePoint 用于回滚. 外层调用失败时, 会回滚内层调用; 但内层调用失败, 不会导致外层调用回滚.
代码中使用 PlatformTransactionManager
手动处理事务
使用 TransactionDefinition
和TransactionStatus
对象来初始化事务
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// execute your business logic here
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);