JAVAPHP尚未看完

MySQL事务初探

2020-06-11  本文已影响0人  潘雪雯

事务是MySQL等关系型数据库区别于NoSQL的重要方面,是保证数据一致性的重要手段。

事务ACID四大特性

原子性(Atomicity)

  1. 分析
    在事务中的扣款和加款两条语句,要嘛都执行,要嘛都不执行。否则如果只执行了扣款语句,就提交,此时如果突然断电,A账户已经发生了扣款,B账号缺没有收到加款,在生活中就会引起纠纷。

一致性(Consistency)

指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。数据库的完整性约束包括但不限于:实体完整性(如行的主键存在且唯一)、列完整性(如字段的类型、大小、长度要符合要求)、外键约束、用户自定义完整性(如转账前后、两个账户余额的和应不变)

  1. 保证原子性、持久性和隔离性,如果这些特性无法保证,事务的一致性也无法保证
  2. 数据库本身提供保障,例如不允许向整行列插入字符串值、字符串长度不能超过列的限制等。
  3. 应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,无无法保证状态的一致。

隔离性(Isolation)

研究的是不同事务之间的相互影响。指事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
考虑最简单的读操作和写操作,可以分为两个方面:

  1. (一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性。
  2. (一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性。(多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题)
写操作之间的相互影响
  1. 表锁在操作数据时会锁定整张表,并发性较差。
  2. 行锁则只锁定需要操作的数据,并发性能好。
    因为加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源,但出于性能考虑 ,绝大多数情况下使用的都是行锁。
写操作对读操作的影响
  1. 脏读: 当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读。


    image.png
  2. 不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。


    image.png
  3. 幻读
    在事务A中按照某个条件先后两次查询数据库,两次查询的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以理解为:前者数据变了,后者是数据的行数变了。


    image.png

    4) 丢失更新
    两个事务同时读取同一条记录,A先修改记录,B也修改记录(B是不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。

  1. MVCC 怎么解决脏读


    image.png

    当事务在T3时间节点读取zhangsan的余额时,会发现数据已被其他事务修改,且状态为未提交。此时事务A读取最新数据后,根据数据的undo log执行回滚操作,得到事务B修改前的数据,从而避免了脏读。

  2. MVCC 怎么解决不可重复读


    image.png

    当事务A在T2节点第一次读取数据时,会记录该数据的版本号(数据的版本号是以row为单位记录的)。假设版本号为1,当事务B提交时,该行记录的版本号增加,假设版本号为2;当事务A在T5再一次读取数据时,发现数据的版本号(2)大于第一次读取时记录的版本号(1),因此会根据undo log执行回滚操作,得到版本号为1时的数据,从而实现可重复读。

  3. MVCC 怎么解决幻读
    InnoDB实现的可重复读是通过next-key lock机制避免幻读现象
    next-key lock是行锁的一种,实现相当于record lock(记录锁)+gap lock(间隙锁);其特点是不仅会锁住记录本身还会锁定一个范围
    image.png
    当事务A在T2节点第一次读取0<id<5的数据时,标记的不只是id=1的数据,而是将范围(0,5)进行标记,这样当T5时刻再次读取0<id<5的数据时,便可以发现id=2的数据比之前标记的版本号更高,此时再结合undo log执行回滚操作,避免幻读。

持久性(Durability)

事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

事务隔离级别

SQL标准中定义4种隔离级别,并规定每种隔离级别下下述几个问题是否存在。一般来说,隔离级别越低,系统开销越低,可支持的并发越高,但隔离性也越差。隔离级别与读问题的关系如下:


image.png

未提交读: 在读数据时不会检查或使用任何锁。因此,在这种隔离级别中可能读取到没有提交的数据。
已提交读: 只读取提交的数据并等待其他事务释放排他锁。读数据的共享锁在读操作完成后立即释放。已提交读是SQL Server的默认隔离级别。
可重复读: 像已提交读级别那样读数据,但会保持共享锁直到事务结束。
可串行读: 工作方式类似于可重复读。但它不仅会锁定受影响的数据,还会锁定这个范围。这就阻止了新数据插入查询所涉及的范围。

来自大佬博客
来自大佬博客

上一篇 下一篇

猜你喜欢

热点阅读