Spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可。
关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。
你可以在启动类中添加如下方法,Debug测试,就能知道自动注入的是 PlatformTransactionManager 接口的哪个实现类。
@EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的
@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);
}
}
这些SpringBoot为我们自动做了,这些对我们并不透明,如果你项目做的比较大,添加的持久化依赖比较多,我们还是会选择人为的指定使用哪个事务管理器。
代码如下:
@EnableTransactionManagement
@SpringBootApplication
public class ProfiledemoApplication {
// 其中 dataSource 框架会自动为我们注入
@Bean
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@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);
}
}
在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
然后在Service中,被 @Transactional 注解的方法,将支持事务。如果注解在类上,则整个类的所有方法都默认支持事务。
对于同一个工程中存在多个事务管理器要怎么处理,请看下面的实例,具体说明请看代码中的注释。
@EnableTransactionManagement // 开启注解事务管理,等同于xml配置文件中的
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {
@Resource(name="txManager2")
private PlatformTransactionManager txManager2;
// 创建事务管理器1
@Bean(name = "txManager1")
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 创建事务管理器2
@Bean(name = "txManager2")
public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
// 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager2;
}
public static void main(String[] args) {
SpringApplication.run(ProfiledemoApplication.class, args);
}
}
@Component
public class DevSendMessage implements SendMessage {
// 使用value具体指定使用哪个事务管理器
@Transactional(value="txManager1")
@Override
public void send() {
System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
send2();
}
// 在存在多个事务管理器的情况下,如果使用value具体指定
// 则默认使用方法 annotationDrivenTransactionManager() 返回的事务管理器
@Transactional
public void send2() {
System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
}
}
注:
如果Spring容器中存在多个 PlatformTransactionManager 实例,并且没有实现接口 TransactionManagementConfigurer 指定默认值,在我们在方法上使用注解 @Transactional 的时候,就必须要用value指定,如果不指定,则会抛出异常。
对于系统需要提供默认事务管理的情况下,实现接口 TransactionManagementConfigurer 指定。
对有的系统,为了避免不必要的问题,在业务中必须要明确指定 @Transactional 的 value 值的情况下。不建议实现接口 TransactionManagementConfigurer,这样控制台会明确抛出异常,开发人员就不会忘记主动指定。
http://blog.csdn.net/catoop/article/details/50595702
注意的几点:
1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
2 默认情况下,一个有事务方法, 遇到RuntiomeException 时会回滚 . 遇到 受检查的异常 是不会回滚 的. 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .
@Transactional 的所有可选属性如下:
属性 | 类型 | 默认值 | 说明 |
propagation | Propagation枚举 | REQUIRED | 事务传播属性 (下有说明) |
isolation | isolation枚举 | DEFAULT | 事务隔离级别 (另有说明) |
readOnly | boolean | false | 是否只读 |
timeout | int | -1 | 超时(秒) |
rollbackFor | Class[] | {} | 需要回滚的异常类 |
rollbackForClassName | String[] | {} | 需要回滚的异常类名 |
noRollbackFor | Class[] | {} | 不需要回滚的异常类 |
noRollbackForClassName | String[] | {} | 不需要回滚的异常类名 |
事务的传播属性 ,有如下可选
可以去看spring源码 : org.springframework.transaction.annotation.Propagation
(用时,导入org.springframework.transaction.annotation.Propagation,再在Transactional括号里用如propagation = Propagation.REQUIRED)
REQUIRED | 业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为. |
SUPPORTS | 如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行. |
MANDATORY | 只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常 |
REQUIRES_NEW | 业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行. |
NOT_SUPPORTED | 声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行. |
NEVER | 声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行. |
NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保证点.内部事务回滚不会对外部事务造成影响, 它只对DataSourceTransactionManager 事务管理器起效. |