Spring事务传播行为
事务传播行为类型 说明
PROPAGATION_REQUIRED(默认) 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
required
外围方法没有事务
在外围方法未开启事务的情况下Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
外围方法有事务
外围方法,内部方法,都开启默认传播行为事务,内部方法的事务会加入到外围方法中。同属于一个事务,若出现异常(就算是手动捕获),也会被感知到,从而事务回滚。
requires_new
外围方法没有事务
新建事务,如果当前存在事务,把当前事务挂起.
外围方法未开启requires_new传播行为的事务,内部方法开启此传播行为的事务,内部方法(多个)各自开启自己的事务,相互独立,互不打扰。
外围方法有事务
外围方法,内部方法,都开启requires_new传播行为的事务,外围方法与内部方法,都是独立新的事务,相当于外围方法事务是A,内部方法事务B,内部方法2事务是C。。。,相互独立。
nested
外围方法没有事务
和required类似
外围方法有事务
外围方法与内部方法都是,nested传播行为事务。内部事务会作为外部方法事务的子事务。若外围事务回滚,内部方法一定回滚,而内部事务回滚,外部不一定回滚(可是否感知到,若内部方法异常被捕获,外部感知不到,则不会回滚)。这和老子与儿子的关系1类似。
使用
配置类
/**
* 声明式事务
* 1, 配置数据源 JdbcTemplate 接管
* 2,配置类加上 @EnableTransactionManagement
*
* 2, crud 方法 加上 @Transactional 注解
* 4, transactionManager 注入这个bean
*/
@EnableTransactionManagement
@Configuration
@ComponentScan("com.szh")
public class TXconfig {
// 从配置文件中 获取数据
@Value("${jdbc.username}")
private String USER;
@Bean("devDataSource")
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(USER);
dataSource.setPassword("123456");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssmbuild");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
// 注意一定要加上 这个
@Bean
public PlatformTransactionManager transactionManager() throws PropertyVetoException {
return new DataSourceTransactionManager(dataSource());
}
}
crud接口上
@Transactional
public void insertBooks(){
源码学习
几个类之间的关系
@EnableTransactionManagement 注解点进去,主要是一个 @Import(TransactionManagementConfigurationSelector.class)
/**
* Indicate how transactional advice should be applied. The default is
*/
AdviceMode mode() default AdviceMode.PROXY;
这个Secector.class点进去:该类只有一个方法,selectImports 方法。
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
// 由于默认是 proxy。所以我们只需要关注 AutoProxyRegistrar 以及 ProxyTransactionManagementConfiguration.class 这两个类
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
AutoProxyRegistrar
主要作用是:往IOC容器中导入某组件。方法:registerBeanDefinitions
主要代码
if (mode == AdviceMode.PROXY) {
// 主要干活的是下面这个语句
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
AopConfigUtils#registerAutoProxyCreatorIfNecessary方法
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 实际上注册的类型是:InfrastructureAdvisorAutoProxyCreator
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
InfrastructureAdvisorAutoProxyCreator类点进去,按快捷键:Ctrl+Alt+U 查看关系图
作用为:为目标Service创建代理对象,增强目标Service方法,用于事务控制。
ProxyTranscationManagementConfiguration
此类三个方法:
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
}
注册BeanFactoryTransactionAttributeSourceAdvisor增强器,该增强器需要如下两个Bean:
TransactionAttributeSource
TransactionInterceptor
重点关注一下:TransactionInterceptor#invoke方法
@Override
public Object invoke(final 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, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
点进去:
主要代码:
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
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.
// 环绕通知。
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清除事务信息
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
可参考
spring声明式事务原理