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事务传播机制详解

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,其他四个隔离级别与数据库的隔离级别一致

  1. ISOLATION_DEFAULT:使用底层数据库的隔离级别,数据库设置的是什么就用什么;
  2. ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
  3. ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
  4. ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
  5. ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。