Spring的事务机制使用统一的机制来处理不同数据访问技术的事务处理。Spring的事务机制提供了一个事务管理器PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现。
数据访问技术 | 实现 |
---|---|
JDBC | DataSourceTransactionManager |
JPA | JpaTransactionManager |
Hibernate | HibernateTransactionManager |
JDO | JdoTransactionManager |
分布式事务 | JtaTransactionManager |
Spring支持声明式事务,即使用注解来选择需要使用事物的方法,它使用@Transactional注解在类上(对该类的所有public方法开启事务)或方法上(对指定方法开启事务)表明开启事务。这是一个AOP的实现操作。
开启注解事务管理需要在配置类上添加@EnableTransactionManagement注解。而如果使用的是JDBC,则可以省略,因为在DataSourceTransactionManagerAutoConfiguration中已经添加了该注解。
关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager 如果添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager(查看DataSourceTransactionManagerAutoConfiguration类) 实例。如果添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager(查看JpaBaseConfiguration类) 实例。
可用于指定使用哪个事务管理器,匹配特定PlatformTransactionManager。如果有项目中只有一个事务管理器,则默认使用该事务管理器。如果项目中有多个事务管理器,则需要设置该值(指定事务管理器)或设置默认的事务管理器,如果不指定则会抛出异常。
设置@Transactional注解的value或者transactionManager属性。
@Transactional(transactionManager="txManager2")
public class UserServiceImpl implements IUserService{
//方法
}
设置默认事务管理器是通过在配置类上实现TransactionManagementConfigurer接口并重写annotationDrivenTransactionManager()方法。
package com.xin;
import javax.annotation.Resource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
@SpringBootApplication
public class Application implements TransactionManagementConfigurer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Resource(name="txManager2")
private PlatformTransactionManager txManager2;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager2;
}
}
指定事务的广播行为,事务的传播行为分7种。
支持当前事务,如果不存在,创建一个新的事务。
支持当前事务,如果不存在,则执行非事务性操作。
支持当前事务,如果不存在则抛出异常。
创建一个新的事务,如果已经存在事务则并挂起当前事务。
不开启事务,如果存在事务则暂停当前事务。
不开启事务,如果存在事务抛出异常。
如果当前事务存在,则在嵌套事务中执行,其行为类似于PROPAGATION.REQUIRED。支持JDBC但是不支持JPA与Hibernate。
REQUIRES_NEW与NESTED的区别
PROPAGATION_REQUIRES_NEW 启动一个新的,不依赖于环境的 “内部” 事务。这个事务将被完全 commited 或 rolled back 而不依赖于外部事务,它拥有自己的隔离范围,自己的锁,等等。当内部事务开始执行时,外部事务将被挂起,内务事务结束时,外部事务将继续执行。
另一方面,PROPAGATION_NESTED 开始一个 “嵌套的” 事务,它是已经存在事务的一个真正的子事务。潜套事务开始执行时,它将取得一个 savepoint。如果这个嵌套事务失败,我们将回滚到此 savepoint。潜套事务是外部事务的一部分,只有外部事务结束后它才会被提交。
由此可见,PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back。
指定事务的隔离级别,事务的隔离级别有4种。
读未提交。可能会发生脏读,不可重复读和幻读。
读已提交。可以防止脏读,但可能会发生不可重复的读取和幻像读取。
可重复读。可以防止脏读与不可重复读,但可能出现幻读。
可串行化。可以防止脏读,不可重复读与幻读。
该值不是事务隔离级别的分类,而是使用当前数据库的默认隔离级别,Oracle、SQLService是READ_COMMITTED,而MySql是REPEATABLE_READ。
此事务的超时。默认为基础事务系统的默认超时。
默认为false。如果事务是只读的可以设置为true。
指定捕获哪个异常类会导致事务回滚。
指定捕获哪个异常类不会导致事务回滚。