数据库基础知识ACID,隔离级别RC,RR,RU,SERIALIZABLE,Phantom Rows幻读,解决幻读,脏读dirty read
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操作。