专栏首页服务端技术杂谈从Spring事务的隔离级别说起

从Spring事务的隔离级别说起

隔离级别(isolation)定义了事务并发的隔离程度。

数据隔离级别分为不同的四种:

  • Serializable :最严格的级别,事务串行执行,资源消耗最大;
  • REPEATABLE READ :保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
  • READ COMMITTED :大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
  • Read Uncommitted :保证了读取过程中不会读取到非法数据。

上面的解释其实每个定义都有一些拗口,其中涉及到几个术语:脏读、不可重复读、幻读。

这里解释一下:

  • 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
  • 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
  • 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。

不可重复读的重点是修改:

  • 同样的条件, 你读取过的数据, 再次读取出来发现值不一样了。

读的重点在于新增或者删除:

  • 同样的条件, 第1次和第2次读出来的记录数不一样。

从控制的角度来看, 两者的区别就比较大:

  • 对于前者, 只需要锁住满足条件的记录。
  • 对于后者, 要锁住满足条件及其相近的记录。

一个对照关系表:Dirty reads non-repeatable reads phantom reads Serializable 不会 不会 不会 REPEATABLE READ 不会 不会 会 READ COMMITTED 不会 会 会 Read Uncommitted 会 会 会

所以最安全的,是Serializable,但是伴随而来也是高昂的性能开销。另外,事务常用的两个属性:readonly和timeout 一个是设置事务为只读以提升性能。另一个是设置事务的超时时间,一般用于防止大事务的发生。还是那句话,事务要尽可能的小!

最后引入一个问题:一个逻辑操作需要检查的条件有20条,能否为了减小事务而将检查性的内容放到事务之外呢?

很多系统都是在DAO的内部开始启动事务,然后进行操作,最后提交或者回滚。这其中涉及到代码设计的问题。小一些的系统可以采用这种方式来做,但是在一些比较大的系统, 逻辑较为复杂的系统中,势必会将过多的业务逻辑嵌入到DAO中,导致DAO的复用性下降。所以这不是一个好的实践。

来回答这个问题:能否为了缩小事务,而将一些业务逻辑检查放到事务外面?

答案是:对于核心的业务检查逻辑,不能放到事务之外,而且必须要作为分布式下的并发控制!

一旦在事务之外做检查,那么势必会造成事务A已经检查过的数据被事务B所修改,导致事务A徒劳无功而且出现并发问题,直接导致业务控制失败。

所以,在分布式的高并发环境下,对于核心业务逻辑的检查,要采用加锁机制。比如事务开启需要读取一条数据进行验证,然后逻辑操作中需要对这条数据进行修改,最后提交。这样的一个过程,如果读取并验证的代码放到事务之外,那么读取的数据极有可能已经被其他的事务修改,当前事务一旦提交,又会重新覆盖掉其他事务的数据,导致数据异常。所以在进入当前事务的时候,必须要将这条数据锁住,使用for update就是一个很好的在分布式环境下的控制手段。

一种好的实践方式是使用编程式事务而非生命式,尤其是在较为规模的项目中。对于事务的配置,在代码量非常大的情况下,将是一种折磨,而且人肉的方式,绝对不能避免这种问题。

将DAO保持针对一张表的最基本操作,然后业务逻辑的处理放入manager和service中进行,同时使用编程式事务更精确的控制事务范围。特别注意的,对于事务内部一些可能抛出异常的情况,捕获要谨慎,不能随便的catch Exception 导致事务的异常被吃掉而不能正常回滚。


本文分享自微信公众号 - 春哥叨叨(chungedaodao),作者:春哥大魔王

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 说说Spring事务的传播机制

    最后琪姐说,修改了Spring的事务传播机制好了(应该是从默认的Required => Requires_New)。

    春哥大魔王
  • 关系数据库和NoSql

    关系数据库历史悠久,可以找到靠谱的DBA,保证关系数据库稳定性,安全性,完整性和性能,同时可以保证监控和分析关系数据库的瓶颈及设计的合理性。成熟的关系数据库有着...

    春哥大魔王
  • Saga分布式事务

    说到分布式事务,大部分人都会知道ACID,两阶段提交,TCC等常见模式。 在微服务大行其道的今天,基于Saga实现的分布式事务则更具普适性。

    春哥大魔王
  • Spring 事务(Transaction)

    疫情期间在家重新读了《Spring in Action》,每次翻阅总有一些收获,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的...

    极客小智
  • Oracle 事务操作

    在看本文之前,请确保你已经了解了Oracle事务和锁的概念即其作用,不过不了解,请参考数据库事务的一致性和原子性浅析和Oracle TM锁和TX锁 1、提交事务...

    郑小超.
  • Spring事务隔离级别

    这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。

    一觉睡到小时候
  • Spring事务机制详解

    Spring事务机制主要包括 声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考。

    lyb-geek
  • MySQL 事务(4)

    数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务...

    兜兜毛毛
  • Spring源码剖析8:Spring事务概述

    事务首先是一系列操作组成的工作单元,该工作单元内的操作是不可分割的,即要么所有操作都做,要么所有操作都不做,这就是事务。

    Java技术江湖
  • [spring事务]一篇浅文让你摆脱事务困扰

    原子性(Atomicity):事物是一个不可分割的工作单位,事物中的操作要么都发生,要么都不发生

    lvgo

扫码关注云+社区

领取腾讯云代金券