Spring事务-'后悔药'

欢迎大家来我的个人博客:https://www.fxyh97.com/index.php/archives/273/

事务是啥,我觉得它是一个后悔药,就是提供给程序一个后悔的机制,出错了的时候可以后悔用的。

说到事务,当然得说四个特性(ACID)喽

  1. 原子性(Atomicity)
    事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。(就比如张三往李四转账了50万,这时候要从张三帐号上扣除50万,然后在李四账号上加上50万,这两个操作要么全部执行成功,要么就全部失败,不可能出现张三扣了钱李四上钱没充值成功,或者张三扣除钱失败,李四上充值成功的结果。这时候这个操作就相当于一个原子性的操作,不能再细分了。)

  2. 一致性(Consistency)
    事务的一致性指的是在一个事务执行之前和执行之后数据之间的关系都必须处于一致性状态。(就比如一个银行一共有100万(张三帐号上有100万,李四帐号上为0元),张三往李四在这个银行的账户上转账了50万,那张三就还有50万,李四也有50万,这个银行的所有帐户加起来就一定是100万,如果不是100万就不一致了。)

  3. 隔离性(Isolation)
    指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。

  4. 持久性(Durability)
    指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。

下面我们再说事务的隔离级别

  1. 事务隔离是事务在数据库读写方面的控制范围。在读取数据库的过程中,如果两个事务并发执行,那么彼此之间的数据是如何影响。

  2. 说隔离级别前我们先说几个名称

    1. 脏读
      脏读是表示两个事务之间,一个事务在修改数据过程中,还没提交事务,但是另外一个事务读取了他修改的数据然后用来进行相关操作,而后来在修改的那个事务没执行成功进行了回滚,就是这个数据恢复了事务执行前的数据,并没有进行修改,而那个读取了事务中的数据进行相关操作的就是错误的数据了,这时候就发生了脏读。

    2. 不可重复读
      不可重复度表示两个事务之间,一个事务在读取这个数据然后进行相关操作,这时候另外一个数据对这个数据进行了修改提交了,然后那个事务再来读这个数据的时候,发现这个数据怎么和我开始读的时候不一样了,这是时候就发生了不可重复读。

    3. 幻读
      幻读表示两个事务之间,一个事务对这个表进行了读取这个条件发现了有10条数据,然后另外一个事务对这个表进行了插入2条数据,也符合一开始那个事务的条件的数据,此时一开始那个事务再读这个条件的时候,怎么变成了12条,这时候就发生了幻读。

    4. 区别不可重复度和幻读:
      不可重复度重修改,幻读重数据数量的变化(删除修改)

  3. 数据库的4个隔离级别

    1. Read Uncommited-读未提交
      这个是隔离级别最低的一个,他允许另外一个事务读取没提交的数据,可能导致脏读,不可重复度,幻读

    2. Read Committed-读提交
      这个隔离级别保证一个事务修改的数据提交后才能被另外一个事务读取,可以防止脏读,但是可能导致不可重复度和幻读

    3. Repeatable Read-可重复读
      这个隔离级别保证一个事务相同条件下前后两次获取的数据是一致的,可以防止脏读和不可重复度,但是可能导致幻读

    4. Serializable-串行
      这个级别保证事务一个一个执行,可以防止脏读、不可重复度和幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

  4. Spring的隔离级别

    • Spring隔离级别多了一个default,就是使用数据库默认的隔离级别
    • 注:sql server,Oracle默认使用的是Read Committed, MySQL默认使用的是Repeatable Read
  5. 在方法上使用注解的方式设置隔离级别

    • import org.springframework.transaction.annotation.Transactional;
      import org.springframework.transaction.annotation.Isolation;
      
      @Transactional(isolation = Isolation.DEFAULT)
      

我们继续说Spring事务的传播行为

  1. 什么是事务的传播

    • 就是当我们在Service中调用别的Service的时候,两个Service的事务该怎么传递
    • 也就是为了解决Service方法之间互相调用的事务问题
  2. 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。

  3. Spring在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

    1. int PROPAGATION_REQUIRED = 0;
      int PROPAGATION_SUPPORTS = 1;
      int PROPAGATION_MANDATORY = 2;
      int PROPAGATION_REQUIRES_NEW = 3;
      int PROPAGATION_NOT_SUPPORTED = 4;
      int PROPAGATION_NEVER = 5;
      int PROPAGATION_NESTED = 6;
      
  4. 其中0、1、2为支持当前事务,3、4、5,为不支持当前事务,6是一个特殊的。

  5. 再说下这7中传播行为

    1. **PROPAGATION_REQUIRED:**如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
    2. **PROPAGATION_SUPPORTS:**如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。
    3. **PROPAGATION_MANDATORY:**如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    4. **PROPAGATION_REQUIRES_NEW:**创建一个新的事务,如果当前存在事务,则把当前事务挂起,等新事务执行完成后再执行挂起的事务。
    5. **PROPAGATION_NOT_SUPPORTED:**以非事务的方式执行,如果当前存在事务,则把当前事务挂起,等新事务执行完成后再执行挂起的事务。
    6. **PROPAGATION_NEVER:**以非事务的方式执行,如果当前存在事务,则抛出异常。
    7. PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;以PROPAGATION_NESTED启动的事务如果存在外部事务的话就内嵌于外部事务中,这个时候内嵌事务并不是一个独立的事务,它依赖于外部事务,只有通过外部的事务提交,自己的事务才会提交;外部事务如果回滚,嵌套的子事务也会回滚。嵌套的子事务不能单独提交。如果不存在外部事务的话就按PROPAGATION_REQUIRED的规则来。

以上便是我对Spring事务的四个特性,以及Spring的隔离级别和传播机制的一些总结,如有不对之处,请帮我指出以便我及时更正。

终于把Spring事务的相关知识也进行了梳理,之前一直对此不怎么了解,在最近工作的时候发现了这块出现了问题,然后再进行各种查询,解决了问题,决定整理一篇博客进行记录。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章