Spring事务

一、spring @Transactional的设置
事物传播行为
事务传播行为就是多个事务方法调用时,如何定义方法间事务的传播。Spring定义了7中传播行为:

  1. propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。
  2. propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
  3. propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
  4. propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
  5. propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
  7. propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。

事物超时设置
  @Transactional(timeout=30)
事务隔离级别
  @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,不可重复读) 基本不使用;
  @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读);
  @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读);
  @Transactional(isolation = Isolation.SERIALIZABLE):串行化;

MYSQL:默认为REPEATABLE_READ级别
SQLSERVER:默认为READ_COMMITTED

脏读:一个事务读取到另一事务未提交的更新数据;
不可重复读 : 在同一事务中,多次读取同一数据返回的结果有所不同,换句话说,后续读取可以读到另一事务已提交的更新数据。相反"可重复读"在同一事务中多次读取数据时,能够保证所读数据一样,也就是后续读取不能读到另一事务已提交的更新数据;
幻读:一个事务读到另一个事务已提交的insert数据;

所谓幻读,指的是当某个事务在读取某个范围内的记录时,另一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom Row)。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。

二、@Transactional注解中常用参数说明
readOnly:用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。
例如:
@Transactional(readOnly=true)

rollbackFor:该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。
例如:
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName:该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。
例如:
指定单一异常类名称:@Transactional(rollbackForClassName=“RuntimeException”)
指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,“Exception”})

noRollbackFor:该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。
例如:
指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)
指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName:该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。
例如:
指定单一异常类名称:@Transactional(noRollbackForClassName=“RuntimeException”)
指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,“Exception”})

propagation:该属性用于设置事务的传播行为。
例如:
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation:该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置。

timeout:该属性用于设置事务的超时秒数,默认值为-1表示永不超时。

注意

  1. ransactional只能被应用到public方法上,如果标记了@Transactional的非public的方法,不会报错,但方法没有事务功能;
  2. 用 spring 事务管理器,由spring来负责数据库的打开、提交、回滚。默认遇到运行期例外会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外不会回滚,即遇到受检查的例外时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常})。如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class);
  3. @Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅是一种元数据,能够被可以识别 @Transactional 注解;
  4. Spring建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。

三、数据库事务正确执行的四个基本要素
事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性);

  1. A (Atomicity) 原子性
    事务里的所有操作要么全部成功,要么全部失败,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

  2. C (Consistency) 一致性
    数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

  3. I (Isolation) 隔离性
    并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。

  4. D (Durability) 持久性
    一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

隔离性的四个级别

READ UNCOMMITTED(未提交读)
在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。这个级别会导致很多问题,从性能上来说,READ UNCOMMITTED不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。

READ COMMITTED(提交读)
大多数数据库系统的默认隔离级别都是READ COMMTTED(但MySQL不是)。READ COMMITTED满足隔离性的简单定义:一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候叫做不可重复读(nonrepeatble read),因为两次执行同样的查询,可能会得到不一样的结果。

REPEATABLE READ(可重复读)
REPEATABLE READ解决了脏读的问题。该隔离级别保证了在同一个事务中多次读取同样记录结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom Read)的问题。

SERIALIZABLE(串行化)
SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE会在读取每一行数据都加锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。

总结
读未提交(Read uncommitted):存在脏读、不可重复读、幻读
读已提交(Read committed):不存在脏读,存在不可重复读、幻读
可重复读(Repeatable read):不存在脏读、不可重复读,存在幻读
可串行化(Serializable):不存在脏读、不可重复读、幻读

四、事务几种实现方式

  1. 编程式事务管理对基于POJO的应用来说是唯一选择,需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理;
  2. 基于TransactionProxyFactoryBean的声明式事务管理;
  3. 基于@Transactional 的声明式事务管理;
  4. 基于Aspectj AOP配置事务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值