spring——事务管理
1.spring支持编程式事务管理和声明式事务管理。
编程式事务管理:编程式事务管理使用TransactionTemplate或者直接使用最底层的PlatformTransactionManager。spring推荐使用TransactionTemplate.
声明式事务管理:声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截。声明式事务管理优于编程式事务管理,不需要在代码中掺杂事务管理的代码,这正是spring提倡的非侵入式开发。
声明式事务管理有两种常用的方式:
1.基于tx和AOP名字空间的xml配置文件。
2.基于@Transactional注解的方式(此方式更简单易用)。
2.基于注解的声明式事务管理配置:
spring.xml配置:
... xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="" ... <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="datasource" ref="datasource"> </bean> <tx:annotation-driven transaction-manager="txManager">
MyBatis自动参与到spring的事务管理中,不需要额外的配置,只需要org.mybatis.spring.SqlSessionFactoerBean引用的数据源和DataSourceTransactionManager引用的数据源一致即可。
3.事务详解:
隔离级别:
在org.springframework.transaction.annotation.Isolation枚举中定义了五个表示隔离级别的值:
public enum Isolation{ DEFAULT(-1); READ_UNCOMMITTED(1); READ_COMMITTED(2); REPEATABLE_READ(4); SERIALIZABLE(4); }
DEFAULT:默认值。表示使用底层数据库默认的隔离级别。对大部分数据库而言,通常这个值就是READ_COMMITTED。
READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的事务。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读(推荐)。
REPEATABLE_READ:该隔离级别表示一个一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。 该级别可以防止脏读和不可重复读。
SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读、幻读。但是会严重影响程序的性能。通过不会用到该级别。
传播行为:
事务的传播行为是指:如果在开始当前事务之前,一个事务上下文已经存在,此时又若干选项可以指定一个事务性方法的执行行为。
在org.springframework.transaction.annotatiopn.Propagation枚举中定义了6个传播行为值:
public enum Propagation{ REQUIRED(0); SUPPORTS(1); MANDATORY(2); REQUIRES_NEW(3); NOT_SUPPORTED(4); NEVER(5); NESTED(6); }
REQUIRED:如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务。
SUPPORTS:如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式继续运行。
MANDATORY:如果当前存在事务,则加入该事务,如果当前没有事务,则抛出异常。
REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
NOT_SUPPORTED:以非事务的方式运行。如果当前存在事务,则把当前事务挂起。
NEVER:以非事务的方式运行。如果当前存在事务,则抛出异常。
NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。如果当前没有事务,则该值等价于REQUIRED。
4.spring事务回滚规则:
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚事务,而抛出checked异常不会导致事务回滚。
@Transactional注解:
该注解的属性:
属性 | 类型 | 描述 |
value | String | 可选的限定描述符,指定使用的事务管理器 |
propagation | enum:Propagation | 可选的事务传播行为设置 |
isolation | enum:Isolation | 可选的事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认:读写 |
timeout | int(in seconds granularity) | 事务超时时间设置 |
rollbackFor | Class对象数组 | 必须继承自Throwable 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组 | 必须继承自Throwable 导致事务回滚的异常类名字的数组 |
noRollbackFor | Class对象数组 | 必须继承自Throwable 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组 | 必须继承自Throwable 不会导致事务回滚的异常类名字的数组 |
用法:
Transactional注解可以作用于接口、接口方法、类、类方法上。当作用于类上时,该类的所有public修饰的方法都具有该类型的事务属性。同时,定义在方法级别上的事务会覆盖此类上的事务属性。
在spring中建议不要直接在接口和接口方法上使用该注解,因为只有在使用基于接口的代理时它才会生效。
另外,@Transactional注解只被使用在public方法上,这是有AOP本质决定的,如果在private、protected、默认可见性方法上并不会引起事务。
默认情况下,只有来自外部的方法调用才会被AOP代理捕获。因此,在类的内部调用本类其他方法并不会引起事务,即使被调用的是public修饰的使用@Trasactional注解的方法。
5.在springboot 使用MyBatis时使用事务时只需要两个注解:
1.在springboot的启动类上添加@EnableTransactionManagement注解
2.在需要的service实现类上或者方法上添加@Transactional注解,一般是在需要的方法上
而这两个注解来自spring-tx.jar包,这个包在添加MyBatis依赖时就已经自动添加了。
例子:
@@SpringBootApplication @EnableTransactionManagement public class StartApplication{ public static void main(String[] args) { SpringApplication.run(MySpringBootApplication.class, args); } }
@Trasactional(readOnly = true) public class UserServiceImpl{ @Transactional(readOnly = false,propagation = Propagation.REQUIRES_NEW,isolation = Isolation.DEFAULT,timeout = 36000,rollbackFoe = Exception.class) public void getUser(){ // do something .... } }
6.多数据源事务管理:
a.配置文件(application.properties):
spring.datasource.prod.driver-class-name=com.jdbc.driver.OracleDriver
spring.datasource.prod.url=jdbc:oracle:thin:@127.0.0.1:3306:prod
spring.datasource.prod.username=root
spring.datasource.prod.password=123456
spring.datasource.dev.driver-class-name=com.jdbc.driver.OracleDriver
spring.datasource.dev.url=jdbc:oracle:thin:@127.0.0.1:3306:dev
spring.datasource.dev.username=root
spring.datasource.dev.password=123456
b.JavaConfig配置类:
// 配置JdbcTemplate模板,在此返回的不是JdbcTemplate,而是其实现接口JdbcOperations.使用@Qualifier指定注入哪个bean,默认名字为该bean的方法名 @Bean public JdbcOperations prodJdbcOperations(@Qualifier("prodDataSource") DataSource prodDataSource ){ return new JdbcTemplate(prodDataSource); } @Bean public JdbcOperations devJdbcOperations(@Qualifier("devDataSource") DataSource devDataSource ){ return new JdbcTemplate(devDataSource); } // 配置事务管理 @Bean public PlatformTransactionManager prodTransactionManager(@Qualifier("prodDataSource") DataSource prodDataSource){ return new DataSourceTransactionManager(prodDataSource); } @Bean public PlatformTransactionManager devTransactionManager(@Qualifier("devDatasource") DataSource devDatasource){ return new DataSourceTransactionManager(devDatasource); } }
c.使用:
@service public class ShopServiceImpl{ @Autowired public JdbcOperations prodJdbcOperations; @Autowired public JdbcOperations devJdbcOperations; @Transactional(value="prodTransactionManager") public void prod(){ prodJdbcOperations.queryForList("SELECT * FROM SHOP"); } @Transactional(value="devTransactionManager") public void dev(){ devJdbcOperations.queryForList("SELECT * FROM SHOP"); } }