spring再学习(二)---spring事务

事务

与关系型数据库一致,事务都遵循 ACID 原则

spring事务

Spring支持编程式事务管理以及声明式事务管理两种方式。

编程式事务管理

  • 编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用底层的PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate
  • 在 Spring 出现以前,编程式事务管理对基于 POJO 的应用来说是唯一选择。用过 Hibernate 的人都知道,我们需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。通过 Spring 提供的事务管理 API,我们可以在代码中灵活控制事务的执行。在底层,Spring 仍然将事务操作委托给底层的持久化框架来执行

声明式事务管理

  • 声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。
  • 编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中
  • 显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置。

开启事务

在spring框架,用注解开启事务@transactional,当然事务有其特性

spring事务的传播行为

  • 事务的传播性一般用在事务嵌套的场景
  • 例:一个事务方法里面调用了另外一个事务方法,那么这两个事务是一起执行,还是只有调用者会执行事务,又或者是只有被调用者会执行事务,这就是需要事务传播机制的配置来确定怎么样执行。
  • spring事务通过propagation属性来定义器传播行为

spring事务的传播行为有7种:

  • propagation_requied
    Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行
  • propagation_reques_new
    该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可。
    大概就是B异常不影响A,B回滚就行了
  • propagation_support
    如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
  • propagation_no_support
    该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
  • propagation_never
    该传播机制不支持外层事务,即如果外层有事务就抛出异常
  • propagation_mandatory
    与NEVER相反,如果外层没有事务,则抛出异常
  • propagation_nested
    该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。

spring事务的隔离级别

事务在运行中可能产生的问题

  • 脏读
    A事务对一条记录进行修改,尚未提交,B事务已经看到了A的修改结果。若A发生回滚,B读到的数据就是错误的,这就是脏读。
  • 不可重复读
    A事务对一条记录进行修改,尚未提交,
    B事务第一次查询该记录,看到的是修改之后的结果,
    此时A发生回滚,B事务又一次查询该记录,看到的是回滚后的结果。
    同一个事务内,B两次查询结果不一致,这就是不可重复读
  • 幻读
    A事务对所有记录进行修改,尚未提交,此时B事务创建了一条新记录,A、B都提交。A查看所有数据,发现有一条数据没有被修改,因为这是B事务新增的,就想看到了幻象一样,这就是幻读

srping有4种隔离级别

spring在事务中使用isolation来配置它

  • isolation_default : 使用后端数据库默认的隔离级别
  • isolation_read_uncommited(读未提交) :允许读取尚未提交的更改。可能导致脏读、幻读或不可重复读
  • isolation_read_commited (读已提交):(Oracle 默认级别)允许从已经提交的并发事务读取。可防止脏读,但幻读和不可重复读仍可能会发生
    • 不可重复读原因:A事务将数据30变成20,B事务查询A提交前的数据为30,(虽然此时A事务已经修改了数据,但是未提交,而该级别事务隔离只能读到已经提交了的数据,也就是30),查询提交后数据为20,B事务看到的数据是不一致的。
    • 幻读原因:A事务修改,B事务新增,B事务提交前,A事务已经提交。B事务提交后,A发现仍有数据未修改。
  • isolation_repeatable_read (可重复读):(MYSQL默认级别)对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可能发生
  • isolation_serializable(序列化):完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的

超时

  • spring在事务中使用timeout来配置它
  • 设置事务的执行时间,当事务超过该执行时间时,强制回滚他

只读

  • spring在事务中使用readonly来配置它
  • 将事务声明为只读:意味着改事务不具有写的操作,只具有读的操作
  • 数据库会因为该属性来做出一些优化设置。例如:不加锁。此时会提高数据库的性能
  • 记住该属性只是声明,如果一个事务中有写的操作,但你依然把他声明为只读,那么代码是不会存在问题的,只是他可能产生脏读、不可重复读、幻读等等问题,因此该属性不能随便加

回滚规则

声明一个事务在出现特定的异常时不回滚,即使特定的异常是运行时异常

  • rollbackFor :因为发生什么异常才回滚
  • norollbackFor:不因为发生什么异常而回滚

你可能感兴趣的:(spring)