欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据库基础知识ACID,隔离级别RC,RR,RU,SERIALIZABLE,Phantom Rows幻读,解决幻读,脏读dirty read

程序员文章站 2022-06-14 17:15:37
...

ACID

A atomicity, C consistency,I isolation, and D durability的缩写,这些特性和事务是紧密联系的,InnoDB事务的特点和ACID原则紧密联系。

  • A 事务是提交和回滚的原子单元,事务对数据库做出更改,不管事务成功commit或者因为失败而回滚。

  • C 在每一个事务被提交或者回滚之后,或者事务在运行过程中,数据库在任何时间是处于一致的状态。如果一个相关的数据正在table中被更新,查询看到的要么是old数据要么是new数据,不会既有old又有new。
    假设用户A和用户B两者的钱加起来一共是700,那么不管A和B之间如何转账,转几次账,这一约束都得成立,即事务结束后两个用户的钱相加起来还得是700,这就是事务的一致性。

  • I 事务在运行过程中总是和其他事务相隔离的,它们不会彼此之间干扰或者看到其他事务未提交的数据。隔离是通过锁机制来实现的,有经验的users能够调整isolation level,在它们确定事务真的不会干扰到彼此的时候,可以减少protection以便支持更好的表现或者concurrency。

  • D 事务的结果是durable的,一次commit操作成功之后,对数据库造成的影响是持久的,即使出现了很多情况,系统崩了等,数据库都已经被改变。持久性会将数据写入到磁盘中,并且会进行冗余备份等。

Transaction Isolation Levels

  • 事务的隔离是数据库处理的基础之一。隔离是ACID中的I,隔离等级设置是为了平衡performance and reliability, consistency, and reproducibility,查询或做出更改时候的几种性能。
  • InnoDB提供了四种事务隔离级别READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABLE,默认是的是RR。
  • 在当前session中更改隔离级别用SET TRANSACTION statement.要更改server的隔离级别需要修改配置文件.
  • InnoDB用不同的锁策略支持每一种隔离级别。你能够将等级升到RR或者释放等级到RC 甚至是RU,比如减少加锁策略比precious consistency和repeatable更优先考虑的时候。SERIALIZABLE用于更加严格的规则,会比RR更高等级,主要用于特定的场合比如XA事务或者并发死锁问题比较严重的时候。

不难得出结论SERIALIZABLE>RR>RC>UC

REPEATABLE READ

      是InnoDB默认的隔离级别,同一个事务中的一致读是读第一次建立的snapshot,同一个事务中的SELECT是不加锁的。关于一致读可以参考我的这篇文章。关于锁的知识,暂时搁置,后续补上是一个比较大的话题。

READ COMMITTED

      每一次的一致读,即使是在同一个事务当中,会设置和读自己的fresh snapshot。RC中会出现幻读的情况,就是说在其它session2中insert 新的row,当前的session1能够看见这个row.

READ UNCOMMITTED

      SELECT语句也是在不加锁的情况执行的,在这个隔离等级下,read操作不具有一致性,也就是会出现dirty read,其它和RC一样。

SERIALIZABLE

      这个隔离级别和RR类似,但是当autocommit启动时,每一个SELECT有自己的事务,因为所有的语句都是一个接着一个执行的,就像串起来一样。

Phantom Rows幻读

定义

      所谓的幻读就是在不同的时间的query中出现了不同的row集合,比如SELECT执行了两次,第二次出现了第一次没有出现的row,这就是幻读。

小例子

      假如在child 这个table中,id上加上索引,你想read and lock表中某一个条件大于100,以便后续更新选中的行。

SELECT * FROM child WHERE id > 100 FOR UPDATE;

      这个查询从第一个行中进行扫描索引,来找出id大于100的值,我们在table中插入id 值为90102的。如果没有锁住扫描这样的范围(这里是90102),另一个session2能够在table中插入id为101的row,如果你在session1中继续执行相同的SELECT语句,你讲会在query结果中看见一条id为101的记录 (a “phantom”) 。

避免幻读,什么解决了幻读

      为了避免幻读,InnoDB使用了一种算法叫做next-key锁和gap锁。InnoDB 使用了row-level锁,当它扫描表的index的时候,它会在遇到的索引记录上设置share型和exclusive型锁。因此,row-level锁就是index-record锁,另外next-key锁是能够影响索引记录之前的“gap”的锁,也就是说next-key锁是index-record锁,gap锁是索引记录之前的gap上的锁。如果一个session 在某一条记录R的索引上有share或者exclusive锁,另一个session是不能在R之前的gap中插入一条新记录的。
      当InnoDB 扫描一个索引时,它也会锁住这个索引之后的gap,就像之前的例子,为了防止在table中插入id大于102的值,InnoDB会用锁锁住id为102之后的gap。
关于锁,之后会仔细进行讨论。

脏读dirty read

      当你读出了其他事务修改但是未提交的数据,这种现象就叫做脏读。这种情况只会出现在RU隔离级别下。
这种操作和数据库设计的ACID不符,它被认为是有风险的,因为数据会被session2回滚或者在提交之前会被修改。session1 使用了脏读出来的数据,然而这些数据还没有被准确地提交。
      它的对立面就是consistent read,InnoDB确保事务不会读到被其他事务更新的数据,即使其它事务同时进行了commit操作。