事务ACID特性及4种隔离级别详解

版权声明:本文为博主原创文章,未经博主允许转载将负法律责任。 https://blog.csdn.net/qq_18312025/article/details/78704862

事务是指对系统进行的一组操作,为了保证系统的完整性,事务需要具有ACID特性,具体如下:

  • 原子性(Atomic)

    一个事务包含多个操作,这些操作要么全部执行,要么全都不执行。实现事务的原子性,要支持回滚操作,在某个操作失败后,回滚到事务执行之前的状态。
    回滚实际上是一个比较高层抽象的概念,大多数DB在实现事务时,是在事务操作的数据快照上进行的(比如,MVCC),并不修改实际的数据,如果有错并不会提交,所以很自然的支持回滚。
    而在其他支持简单事务的系统中,不会在快照上更新,而直接操作实际数据。可以先预演一边所有要执行的操作,如果失败则这些操作不会被执行,通过这种方式很简单的实现了原子性。

  • 一致性(Consistency)

    一致性是指事务使得系统从一个一致的状态转换到另一个一致状态。事务的一致性决定了一个系统设计和实现的复杂度。事务可以不同程度的一致性:
    强一致性:读操作可以立即读到提交的更新操作。
    弱一致性:提交的更新操作,不一定立即会被读操作读到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。
    最终一致性:是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。
    其他一致性变体还有:
    单调一致性:如果一个进程已经读到一个值,那么后续不会读到更早的值。
    会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。

  • 隔离性(Isolation)

    并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。在事务并发操作时,可能出现的问题:

    • 脏读:
      • 事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
    • 不可重复读:
      • 在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。
    • 幻读:
      • 在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。
  • 持久性(Durability)

    • 事务提交后,对系统的影响是永久的。

事务的隔离级别从低到高有:

  • Read Uncommitted(读未提交):
    • 最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
  • Read Committed(读已提交):
    • 只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
  • Repeated Read(重复读):
    • 在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
  • Serialization(串行化):
    • 事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。
      通常,在工程实践中,为了性能的考虑会对隔离性进行折中。

ANSI/ISO SQL标准定义了4种事务隔离级别,这些隔离级别是根据事务并行出现的4个“现象”定义的。
4个现象是:

  • 1.更新丢失(Lost Update):A和B同时写

    例:
    1.事务A将数值改为1并提交;
    2.事务B将数值改为2并提交。
    这时数据的值为2,事务A所做的更新将会丢失。
    解决办法:对行加锁,只允许并发一个更新事务。

  • 2.脏读(dirty read):A改后还未提交,B读,A又改并提交

    例:
    1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)
    2.Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!
    3.而财务发现操作有误,回滚了事务,Mary的工资又变为了1000, 像这样,Mary记取的工资数8000是一个脏数据。

  • 3.不可重复读(nonrepeatable read):A先读,B再改,A再读

    例:
    1.在事务A中,Mary 读取了自己的工资为1000,操作并没有完成
    2.在事务B中,这时财务人员修改了Mary的工资为2000,并提交了事务.
    3.在事务A中,Mary 再次读取自己的工资时,工资变为了2000
    解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。

  • 4.幻读(phantom read):A改后还未提交,B改其他的,A再查

    例:
    1.A把所有的“黑色”改为“白色”
    2.B把所有的“红色”改为“黑色”
    3.A再查询黑色,却发现还有一批。

根据对4个现象的避免程度,事务的4个隔离级别是:

  • Read Uncommited:读未提交数据(解决了更新丢失)
  • Read Commited:读已提交的数据(解决了更新丢失、脏读)
  • Repeatable Read:可重复读(解决了更新丢失、脏读、不可重复读)
  • Serializable:串行化(全部解决了)

四个级别与四种现象的关系是:

英文 更新丢失 脏读 不可重复读 幻读
Read Uncommited 读未提交 不会出现 会出现 会出现 会出现
Read Commited 读已提交 不会出现 不会出现 会出现 会出现
Repeatable Read 可重复读
不会出现 不会出现 不会出现 会出现
Serializable 串行化 不会出现 不会出现 不会出现 不会出现

大多数数据库的默认隔离级别为: Read Commited,如Sql Server , Oracle
少数数据库默认的隔离级别为Repeatable Read, 如MySQL InnoDB存储引擎

tr_isolation(隔离)参数:
可以设置mysql的隔离级别

这里写图片描述

tr_isolation:可选值有

  • READ-UNCOMMITED
  • READ-COMMITED
  • REPEATABLE-READ
  • SERIALIZABLE

Create By LPeng

没有更多推荐了,返回首页