Spring事务管理
Spring事务分为两种:
- 声明式事务(通过配置或注解使用,通过AOP实现)
- 编程式事务(通过代码的方式实现)
声明式事务
使用 @Transactional
注解进行事务管理。
注意点:
- 引入Spring的@Transactional注解。不要引入其他包里的。
- 要在public方法上,除非特殊配置,(如使用AspectJ静态织入实现AOP)。因为Spring动态代理默认是AOP,对目标方法进行增强,不能代理到private方法。
- 必须通过代理过的类从外部调用目标方法才能生效。Spring通过AOP对方法进行增强,所以要调用增强的方法必须是调用代理后的对象。
- 异常抛出了标记@Transactional注解的方法,事务才能回滚。
- 默认情况下,出现RuntimeException或Error的时候才会回滚。
编程式事务
几个重要接口:
-
PlatformTransactionManager
: (平台)事务管理器,Spring 事务策略的核心。具体实现交给不同的持久化框架来完成。spring-boot-starter-jdbc
默认注入DataSourceTransactionManager
,spring-boot-starter-data-jpa
默认注入JpaTransactionManager
,Hibernate默认注入HibernateTransactionManager
-
TransactionDefinition
: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。 -
TransactionStatus
: 事务运行状态。
查看具体的事务管理器
@EnableTransactionManagement // 启注解事务管理
@SpringBootApplication
public class ProfiledemoApplication {
@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager){
System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
return new Object();
}
public static void main(String[] args) {
SpringApplication.run(ProfiledemoApplication.class, args);
}
}
编程式事务
/**
*
* @param dataSource 要执行这个sql的数据源
*/
public void demo(DataSource dataSource) {
// 当前具体的事务管理器
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();//事务定义类
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);// 返回事务状态对象
try {
/*
...... 执行sql
*/
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}
2021年8月30日
补充:
spring 声明式事务+MySQL数据库执行DDL语句后不能回滚。
原因:
- MySQL默认是开启autocommit的,即每一条DML语句都会被作为一个单独的事务进行隐式提交。
- 如果使用begin或start transaction显式开启一个事务,则需要显示的commit或rollback来结束事务。
- 一个事务内执行DDL会触发隐式提交
优先级:
spring事务管理默认自动提交为false,jdbc为true,一般连接池是true(oracle),MySQL和Oracle默认是true。
一般优先级是:手动设置覆盖默认设置,即spring或者是druid可以覆盖MySQL配置的autocommit。
对于spring和druid来说,后设置的会覆盖前面设置的。
执行完DDL语句之后会直接commit DDL和之前的语句,所以rollback只能回滚到执行DDL语句后。即使将autocommit为false,依然无法回滚。