Spring 事务
Spring事务中的使用方法常见的有两种,一种是编程式事务,一种是声明式事务。
编程式事务目前使用的较少,一般是jdbc进行数据库操作而没有引入其他框架时,就需要通过手动编写事务进行处理。
声明式事务
@Transactional,在实际开发中,对于一组数据库操作特别是增删改操作,为了保证原子性,通常需要用事务来控制,要么全部成功,要么全部失败。尽可能将Mysql执行语句放到方法体后面靠。因为MySQL事务的commit语句是在第一次执行MySQL相关语句开始,一直到方法的结束。
@Transactional
public void testTransaction(User user) {
int rowNum = userMapper.insertUser(user);
doSomething(); // 这个doSomthing 可能耗时较长
List<User> userList = userMapper.selectAllUsers();
}
@Transactional详细介绍
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
//用于设置隔离级别。
Isolation isolation() default Isolation.DEFAULT;
//timeout用于设置超时时间,如果不设置,则为默认值-1,表示没有超时时间
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
//设置事务为只读事务:可以进行事务优化。
//readOnly=true,加快查询速度;不用考虑事务那一堆操作。
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
//让原本不会滚的异常回滚,必须使用throws。
//事务的回滚,默认发生运行时异常回滚,默认编译时异常不回滚。
String[] rollbackForClassName() default {};
//让原本回滚的而异常不回滚
//指哪些异常不需要回滚
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
Spring事务的传播行为
传播行为(事务的传播和事务的行为),如果有多个事务进行嵌套运行,子十五是否要和大事务共用一个事务。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行,事务的传播行为可以有传播属性指定。
传播属性 | 描述 |
REQUIRED | 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行 |
REQUIRED_NEW | 当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将他挂起。 |
SUPPORTS | 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中 |
NOT_SUPPORTED | 当前的方法不应该运行在事务中,如果有运行的事务,将他挂起 |
MANDATORY | 当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常 |
NEVER | 当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常 |
NESTED | 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行 |
Spring事务 本类事务方法之间调用就是一个事务
在同一个类中调用具有@Transactional(propagation=Propagation.REQUIRED_NEW)注解的方法,会发现不会创建一个新的事务,所有的方法都在一个事务中。
为什么会这样?
如果是MulService --mulTx()—调用bookService两个方法和Bookservice–mulTx–直接调用两个方法,有什么区别。
MulServiceProxy.mulTx(){
bookserviceProxy.checkout();
bookserviceProxy.updatePrice();
}
BookServiceProxy.mulTx(){
checkout();
updatePrice();
}
Spring事务隔离
spring有五种隔离级别,默认值为ISOLATION_DEFAULT,其他四个隔离级别与数据库的隔离级别一致
- ISOLATION_DEFAULT:使用底层数据库的隔离级别,数据库设置的是什么就用什么;
- ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
- ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
- ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
- ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。