事务隔离级别介绍
ACID特性
1.原子性atomicuty
即是事务在提交的过程中,要么全部提交,要么全部不提交,成功提交之后,持久化更新;提交失败,本次事务全部回滚。【非0即1】这是保证数据一致性的关键
2.一致性consistency
在事务提交之后,数据处于一致性的状态。
3.隔离性isolation
每一个事务相对其他事务来说是黑盒的,透明的,独立的。各个事务之间的执行是不会交叉的。
4.持久性durability
在一次事务提交之后,对数据表的影响就是永久的,直到被其他事务再次修改。
四种隔离级别
根据数据读写的组合2*2=4,中组合关系。
1. 修改时允许修改 – 丢失更新
2. 修改时允许读 – 脏读
3. 读时允许修改 – 不可重复读
4. 读时允许插入 – 幻读(比预想读取的数据多)
从上到下,问题越来越不严重,但是性能开销越来越大。
事务的四中隔离级别为:
1.read uncommitted – 读取未提交
所有的事务都可以看到其他事务未提交的数据,这种隔离级别在应用中是很少使用到的。在一个事务更新的时候,另外一个事务读取。虽然能够保证了数据的更新,但是可能会出现脏读。
2.read committed – 读取提交
在一个事务未提交之前另一个事务是不可以读取。这是一般数据库(不包括Mysql)的默认隔离级别,但是可能会出现不可重复读。
只要其中的一个事务发生commit,由此引起的数据变化都会被其他事务感知,造成的后果可能是另一个事务前后两次读取的数据不一致--不可重复读.
【在一个事务处理期间可能有新的事务提交】这就导致了可能出现两次读取的数据是不一致的。
3.repeatable read – 重复读取
这是mysql的默认隔离级别。在一个事务读取的时候,不允许其他事务修改数据,但是允许插入数据,所以可能出现幻读。使用间隙锁(next-key locking)MVCC的方式实现幻读的防止,间隙锁使得InnoDB锁定查询的涉及的行,还会对索引中的间隙进行锁定,为了防止幻读数据的插入。可能出现幻读的情况:本事务在做更新操作的时候,如果被更新的数据包含其他事务中新增的数据,那么本事务在更新完前后读取内容是不一样的—幻读.
例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
e.g
事务A:repeatable
start transaction;
insert into temp ....values(new...)
commit;
事务B:repeatable
start transaction;
select * from temp;
update temp set ...//对所有数据修改,覆盖到上面新插入的数据.
select * from temp;
在这种情况下,就会出现事务B 两次读取的数据是不一样的,第二次读会比第一次的数据多.
4.serializable 串行化。
强制事务执行的串行化。每一次查询都会加上共享锁(lock in share mode)
事务隔离级别与并发问题
隔离级别(以此增强) |
脏读(读时提交) |
不可重复读(读时更新) |
幻读(读时插入) |
read uncommitted |
√ |
√ |
√ |
read committed |
× |
√ |
√ |
repeatable read |
× |
× |
√ |
serializable |
× |
× |
× |
事务隔离级别的更改
SET [GLOBAL | SESSION]TRANSACTION ISOLATION LEVEL [REPEATABLE READ |READ COMMITTED |READ UNCOMMITTED |SERIALIZABLE
GLOBAL关键字可以修改全局的设置,修改完之后对已经建立的连接还不会生效,对新连接才会生效。
SESSION 关键字在修改完之后立即生效,不会对其他连接生效。
没有关键字:
没有两个关键字的执行方式,本连接的当前事务不会起作用,只会在本连接的下一个事务才会起作用。
MVCC
在mysql中,mvcc是行级锁的一个变种,它避免了加锁的操作,降低加锁的开销,提升并发度。InnoDB中mvcc的实现:
在每一条记录的后面有两个隐藏的字段。一个是保存了记录的创建时间,另一个是保存行的过期时间(删除时间),这里说的时间不是传统意义上的时间,而是一个版本号。当开始一个新事务的时候版本号就会递增。
SELECT操作
Innodb会根据下面的两个条件来检查每条记录
【a】.InnoDB只会检查创建版本早于当前事务版本的行(也就是记录的创建版本小于或等于当前事务的版本),这样保证选取的行在事务开始之前已经存在,或者事务自身插入或修改过。
【b】.行的删除版本要么未定义,要么大于当前事务的版本。这样保证选取的记录在知晓能够该事务的时候未被删除。
INSERT
将新插入的记录的创建版本设置为当前事务版本。
UPDATE
插入一条新的数据,将当前版本作为新记录的创建版本,将当前事务版本号赋值给原始记录的删除版本。
DELETE
将当前事务版本号赋值给要删除的记录的删除版本。
之前自己参考王珊数据库系统概论理解和总结的四种隔离级别。不过innodb的锁还没有进一步学习,只是知道在repeatable read 级别下innodb是不会有幻影读的,我猜where的时候是锁全表。
数据库的并发操作带来数据的不一致性有丢失修改,不可重复读,读脏数据。如下表。其中不可重复读有三种情况。另外两种为:1 事务T1按照一定条件读取了某些数据,T2删除了部分记录,T1再次按相同条件读取记录时,发现有数据莫名消失。2 事务T1按照一定条件读取了某些数据,T2插入了符合T1条件的数据,T1再次按照相同条件读数据时,发现莫名多出数据。这两种情况叫做幻影读。
T1 |
T2 |
T1 |
T2 |
T1 |
T2 |
read A=1 A=A+1
Write A
|
read A=1 A=A+1 Write A
|
read A read B C=A+B=2
read A read B C=A+B=3 |
read A A=A+1 Write A
|
read A=1 A=A+1 Write A
rollback |
read A=2
|
a丢失修改 |
b不可重复读 |
c读脏数据 |
其中不可重复读有三种情况。另外两种为:1 事务T1按照一定条件读取了某些数据,T2删除了部分记录,T1再次按相同条件读取记录时,发现有数据莫名消失。2 事务T1按照一定条件读取了某些数据,T2插入了符合T1条件的数据,T1再次按照相同条件读数据时,发现莫名多出数据。这两种情况大家都叫做幻影读。
所以需要封锁技术控制并发操作。
锁类型:
X锁,写锁,排他锁,exclusive locks用于数据写操作前进行锁定。如果事务T对数据A加上X锁,就只允许事务T读取和修改数据A,其他事务不能对数据A再加任何锁,但可以读。直到事务T释放A上的锁才能
S锁,读锁,共享锁,share locks 用于数据读操作前进行锁定。如果事务T对数据A加上了S锁,事务T就只能读取数据A但不可以修改,其他事务可以再对数据A加S锁执行读取操作,只要数据A上有S锁,任何事物都只能对其加S锁而不能加X锁修改。
封锁粒度和意向锁这里就不讨论了。
锁的持续时间:
在基于锁的并发控制中,隔离级别决定了锁的持有时间。"C"-表示锁会持续到事务提交。"S" –表示锁持续到当前语句执行完毕。如果锁在语句执行完毕就释放则另外一个事务就可以在这个事务提交前修改锁定的数据,从而造成混乱。
隔离级别 |
写操作 |
读操作 |
范围操作(...where...) |
未授权读 |
S |
S |
S |
授权读 |
C |
S |
S |
可重复读 |
C |
C |
S |
可序列化 |
C |
C |
C |
由这两种锁组合形成的四种隔离级别也有叫封锁协议
一级封锁协议--未授权读取(Read Uncommitted)
事务T在修改数据A之前必须先对其加X锁,直到事务结束才释放X锁
假设A和B初始都为1
T1 |
T2 |
T1 |
T2 |
T1 |
T2 |
Xlock A A=A+1 Write A commit Unlock A
|
等待 等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
read A read B C=A+B=2
read A read B C=A+B=3
|
Xlock A A=A+1 Write A commit Unlock A
|
Xlock A A=A+1 Write A
rollback Unlock A
|
read A=2
|
a正确 |
b不可重复读 |
c读脏数据 |
其中c读脏数据是这样理解的,事件T1对A加了排他锁,对数据A进行了修改,若事件T2对A申请锁,则会wait;若事件T2不对A申请任何锁,则即使A加对A加了排他锁,T2也会无视。
二级封锁协议--授权读取(Read Committed)
一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁
T1 |
T2 |
T1 |
T2 |
T1 |
T2 |
Xlock A A=A+1 Write A commit Unlock A
|
等待 等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
Slock A Slock B read A read B C=A+B=2 commit Unlock A Unlock B
等待 等待 Slock A Slock B read A read B C=A+B=3 commit Unlock A Unlock B |
等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
Xlock A A=A+1 Write A
rollback Unlock A
|
等待 等待 等待 · · · · Slock A read A Unlock A |
a正确 |
b不可重复读 |
c正确 |
三级封锁协议--可重复读取(Repeatable Read)
一级封锁协议加上事务T在读取数据A之前必须先对其加S锁,直到事务结束才释放。
T1 |
T2 |
T1 |
T2 |
T1 |
T2 |
Xlock A A=A+1 Write A commit Unlock A
|
等待 等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
Slock A Slock B read A read B C=A+B=2
Slock A Slock B read A read B C=A+B=3 Unlock A Unlock B
|
等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
Xlock A A=A+1 Write A
rollback Unlock A
|
等待 等待 等待 · · · · Slock A read A Unlock A |
a正确 |
b T1读操作是正确的 但是T1范围读是会出现幻影读的 |
c正确 |
三级锁的在使用范围条件的时候会发生幻影读,比如一个事务两个类似的查询的时候
T1 |
T2 |
select count[id] from user where id>10 Slock id [id>10] count[id]=0 也就是这里锁了0行 commit
select count[id] from user where id>10 Slock id [id>10] count[id]=0 commit Unlock |
insert into user values [id=11] commit
|
幻影读 |
两段封锁协议--序列化(Serializable)
对任何数据进行读写之前,必须对该数据加锁包括使用where的范围读。在释放一个封锁之后,事务不再申请和获得任何锁,只能继续释放锁,直到事务结束。
T1 |
T2 |
T1 |
T2 |
T1 |
T2 |
Xlock A A=A+1 Write A commit Unlock A
|
等待 等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
Slock A Slock B read A read B C=A+B=2
read A read B C=A+B=3 Unlock A Unlock B
|
等待 等待 等待 Xlock A A=A+1 Write A commit Unlock A
|
Xlock A A=A+1 Write A
rollback Unlock A
|
等待 等待 等待 · · · · Slock A read A Unlock A |
a正确 |
b正确--不带范围的操作 |
c正确 |
两段锁在使用范围操作的时候不会发生幻影读
T1 |
T2 |
select count[id] from user where id>10 Slock id [id>10] count[id]=0
select count[id] from user where id>10 count[id]=1 commit Unlock
|
等待 等待 等待 等待 等待 等待 等待 insert into user values [id=11] commit
|
正确 |
数据完整性
是指数据的精确性(Accuracy)和可靠性(Reliability),它是为防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。数据完整性分为实体完整性(Entity Integrity)、域完整性(Domain Integrity)、参照完整性(Referential Integrity)、用户自定义完整性(User-defined Integrity)。
1.实体完整性,保证数据库中每一条记录的唯一性。数据表中的UNIQUE ,PRIMARYKEY,IDENTITY就是完整性的体现。
2.域完整性。保证数据库中列满足某种数据类型或约束,比如数据类型,数据精度,数据取值范围等。在数据库中的体现就是CHECK,FOREIGN KEY,DEFAULT,NOT NULL等。
3.参照完整性。它要求两个或多个表主键与外键数据的一致性。防止数据丢失或无意义的数据在数据库中扩散。
4.用户自定义完整性。不同的数据库环境需要一些特殊的约束条件。它反应一些特殊的应用需要满足的约束条件。
数据一致性
是指事务执行的结果必须从一个一致性状态变到另外一种一致性状态。保证数据一致性是指当事务完成时,所有的数据都处于一致性的状态。在关系性数据库中,在事务提交之后,所有定义的规则都应当被应用到事务的修改上,保证每一条记录存储的数据信息是完整的一致的。