现如今,对于一个Java程序猿来说,如果说不会用甚至不知道Spring,那肯定不是一个合格的Java程序猿。大家都知道,Spring最主要的俩大模块,分别是IoC和AOP。而今天主要讲的是Spring中的事务@Transactional注解。Sping事务的传播机制
| 名称 | 解释 |
|---|---|
| TransactionDefinition.PROPAGATION_REQUIRED | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 |
| TransactionDefinition.PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
| TransactionDefinition.PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 |
| TransactionDefinition.PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
| TransactionDefinition.PROPAGATION_NEVER | 以非事务方式运行,如果当前存在事务,则抛出异常。 |
| TransactionDefinition.PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
| TransactionDefinition.PROPAGATION_NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。 |
基于Spring AOP来实现Spring事务,加了注解@EnableTransactionManagement开启事务后,在类或者public方法上加上@Transactional注解就可以了。
pom.xml
org.springframework spring-context5.3.10 org.springframework spring-jdbc5.3.10 mysql mysql-connector-java5.1.47
AppConfig.java
@ComponentScan("com.nxj.dev")
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
// 默认是true(事务 部分失败时,全局回滚)
// 如果是false(事务 部分失败时,不回滚,都提交)
// transactionManager.setGlobalRollbackOnParticipationFailure(true);
return transactionManager;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://ip:3306/spring_transaction?characterEncoding=utf-8&useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}
OrderService.java
@Component
public class OrderService {
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
OrderService orderService;
// 1和2和3都插入失败
@Transactional
public void test1() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
// 报错:java.lang.ArithmeticException: / by zero
// Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
// 而ArithmeticException是RuntimeException的子类
int i = 1/0;
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
}
// 1和2和3都成功
@Transactional
public void test2() throws SQLException {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
// Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
throw new SQLException();
}
// 1和2和3都失败
@Transactional(rollbackFor = Exception.class)
public void test3() throws SQLException {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
// Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
throw new SQLException();
}
// 1和2和3都失败
@Transactional
public void test4() throws RuntimeException {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
// Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
// throw new RuntimeException();
throw new Error();
}
// 1和2都插入成功,3 失败
public void test5() {
a();
}
// 1和2和3 都失败
public void test6() {
// 在同一个类中,非事务方法调用事务方法,事务失效,得采用(Service)AopContext.currentProxy().xx()来进行调用,事务才能生效。
((OrderService) AopContext.currentProxy()).a();
}
// 1和2和3 都失败
public void test7() {
// 在同一个类中,非事务方法调用事务方法,事务失效,也可以采用自己注入自己,事务能生效。
orderService.a();
}
@Transactional
public void a() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
// 报错:java.lang.ArithmeticException: / by zero
int i = 1/0;
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
}
// 1和2和3都失败
@Transactional
public void test8() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
b();
}
// 加不加@Transactional注解,都无所谓,因为同一个类中方法之间直接调用,被调用的方法上@Transactional失效
@Transactional
public void b() {
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
int i = 1/0;
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
}
// 1和2成功,3失败
@Transactional
public void test9() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
try {
b();
} catch (Exception e) {
}
}
// 1和2和3失败
@Transactional
public void test10() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
try {
b();
} catch (Exception e) {
//手动强制回滚事务,然后可以抛出自定义的异常给前端
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
// 1和2和3失败
@Transactional
public void test11() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
try {
orderService.b();
} catch (Exception e) {
}
}
// 1和2都成功,3失败
@Transactional
public void test12() {
// 1
jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
orderService.c();
}
@Transactional
public void c() {
try {
// 2
jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
int i = 1/0;
// 3
jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
} catch (Exception e) {
}
}
}
@EnableTransactionManagement
@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;
}
可以看到,这个注解也挺简单的,就是通过@Import注解,引入了另外一个bean,通过查看TransactionManagementConfigurationSelector的类继承关系,可以发现,这个类实现了ImportSelector注解,所以,会实现selectImports()方法,在该方法中,注入了两个重要的bean
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
AutoProxyRegistrar
AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以,在registerBeanDefinitions方法中,注入一个bean
InfrastructureAdvisorAutoProxyCreator 可以发现,这个类是一个后置处理器,继承了InstantiationAwareBeanPostProcessor
所以:这就是@EnableTransactionManagement的第一个作用,注入了一个后置处理器,这个后置处理器就是用来对事务注解进行增强的
ProxyTransactionManagementConfiguration
该类只有一个注解@Configuration,所以该类是一个配置类,在该类中,通过三个@Bean注解,向spring容器中注入了事务执行时要用到的组件
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//事务增强器会解析事务注解的参数信息
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
所以:该类是给spring容器中,注入了三个bean,分别是:事务拦截器、事务解析器、事务增强器
Advisor=Advice+Pointcut
其中
Advisor=>BeanFactoryTransactionAttributeSourceAdvisor
Advice=>TransactionInterceptor
Pointcut=>TransactionAttributeSource=>TransactionAttributeSourcePointcut
参考链接:spring事务源码-代理对象生成过程解析_小小少年_的博客-CSDN博客_spring 事务代理对象
参考链接:公司新来一个同事,把 @Transactional 事务注解运用得炉火纯青。。



