前言
前边有一篇《Mysql-各种锁区分与【MVCC】》简单说明了一下mvcc,本篇再次展开叙述。
通常为了获得更好的运行性能,各种
数据库
都允许多个事务同时运行,这就是
事务并发处理
。当并发的事务访问或修改数据库中相同的数据时,通常需要采取必要的隔离机制,反之会出现各种并发问题,mvcc就是来解决事务并发处理下的问题的。
一句话总领一下本篇内容:
对于innodb,通过4种隔离级别的MVCC(多版本并发控制),实现事务并发事务处理,解决并发问题(脏读,不可重复读,幻读)。
每种级别解决的问题也不一样,事务等级越严格,并发副作用越低,付出的代价越大
好可能还是不太明白,详细看看下边吧~
一.并发事务处理:
1.实现方式:a.悲观锁;b.MVCC
2.优点
3.缺点
二.事务隔离机制
1.四种问题(副作用)
2.四种隔离级别(解决上边问题)
3.四种问题情境描述
三.相关命令
四.总结
一.并发事务处理
:
1.实现方式:
a.悲观锁
:在读取数据前,对其加锁,阻止其他事务对数据进行修改
b.MVCC(多版本并发控制)
: 不加任何锁,通过一定机制生成
一个数据请求时间点的一致性数据快照
(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取。从用户的角度来看,好像是数据库可以提供同一数据的多个版本,因此,这种技术叫做数据
多版本并发控制
(MultiVersion Concurrency Control,简称MVCC或MCC)。
2.优点
:
并发事务处理能大大增加数据库资源的
利用率
,提高数据库系统的
事务吞吐量
,从而可以
支持更多的用户
。
3.缺点
:
但并发事务处理也会带来一些问题,主要包括以下几种情况。(更新丢失,脏读,不可重复读,幻读)
“更新丢失”
通常是应该完全避免的。但防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决,因此,防止更新丢失应该是应用的责任。
“脏读”、“不可重复读”和“幻读”
,其实都是数据库读一致性问题,必须由数据库提供一定的
事务隔离机制
来解决。
二.事务隔离机制
有四种事务隔离机制,越高的机制可以处理更多的副作用。
1.四种问题(副作用):
a.更新丢失
b.脏读
c.不可重复读
d.幻读
2.四种隔离级别(解决上边问题):
1).未 提 交 读:解决-a【最基本】
2).已 提 交 读:解决-a,b
3).可 重 复 读:解决-a,b,c【默认的级别】
4).可 序列化读:解决-a,b,c,d
3.四种问题情境描述:
a.更新丢失:
Lost Update 两个事务同时对一字段处理,出现其中一个丢失现象
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题--
最后的更新覆盖了由其他事务所做的更新
。
num=100
a update set num+=1 num=101
b update set num+=2 num=102
a先提交 b再提交,a的更新丢失
b.脏读:
Drity Read
一个事务正在对一条记录做修改,
在这个事务完成并提交前,这条记录的数据就生效了处于不一致状态
;这时,另一个事务也来读取同一条记录,如果不加控制,
第二个事务
读取了这些“脏”数据
,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做"脏读"。
a begin transaction
a insert 事务未提交,
b select (可以看到a的insert),
a rollback
b select (看不到a的insert)
从头到尾b蒙圈儿了,他就read了两次,结果却不同,此为脏读。
c.不可重复读:
Non-repeatable Read
一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,
却发现其读出的数据已经发生了改变(
update
)、或某些记录已经被删除(
delete
)了
!这种现象就叫做“不可重复读”。(若是发生了insert,那么这种现象就叫幻读了,如下)
a begin transaction
a select (第一次查询的结果)
b begin transaction
b update|delete
b commit
a select (第二次查询的结果,与第一次不相同,不重复,简称不可重复读)
a commit
a在一个事物里读两次数据不同,造成a里的其他事物操作产生偏差,(能控制b编辑完a在 整体操作就好了)
d.幻读:
Phantom Read 指的是插入新行,update|delete不归为幻读
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入(insert)了满足其查询条件的新数据,这种现象就称为“幻读”。
a begin transaction
a select where ID>100 ,(假如只有101一条数据)
b insert ID=102,(这里是insert表示幻读,要是为update,就成不可重复读了)
b commit
a select where ID>100 (有101,102两条数据)(b no commit能读出来叫脏读;b commit 叫不可重复读)
a begin transaction
a查询了两次,返回的数据行竟然不相等
三.相关命令
1.查看当前会话隔离级别
select @@tx_isolation;
2.查看系统当前隔离级别
select @@global.tx_isolation;
3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;
4.设置系统当前隔离级别
set global transaction isolation level repeatable read;
5.命令行,开始事务时
set autocommit=off 或者 start transaction
四.总结
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大。
所以不是越严格越好的,许多应用场景对不可重读和幻读并不敏感,可能更关心数据库的并发访问能力。
根据自己的业务逻辑要求来平衡“隔离”和“并发”矛盾。
参考书籍:《深入浅出MySQL》