详解mysql 事物隔离级别与锁机制
事物隔离级别
⾸先看下数据库事物四⼤特性,ACID,,⼀致性,隔离性,持久性。
隔离性:由并发事务所作的修改必须与任何其它并发事务所作的修改隔离,互相不受影响。同⼀时间,只允许⼀个事务请求同⼀数据,不同的事务之间彼此没有任何⼲扰。mysql具有四种事物隔离级别,隔离⼒度依次递增,⾼度隔离会限制可并⾏执⾏的事务数,所以⼀些应⽤程序降低隔离级别以换取更⼤的。不同业务场景下使⽤不同的数据库事物隔离性,部分关键业务采⽤隔离性⾼的隔离级别,以保证数据正确性。
msyql 四种事物隔离级别:
1. Read Uncommitted(读未提交):事物能读到不同事物没有提交(未commit)的数据结果,实际应⽤⽐较少,会产⽣脏读,事物已经读到其他事物未提交的数据,但数据被回滚,称为脏读。
2. Read Committed(读已提交):事物读取其他事物已经提交的数据,读取到的是最新的数据,所以会出现在同⼀事物中select读取到的数据前后不⼀致,会出现不可重复读问题,不可重复读问题就是我们在同⼀个事务中执⾏完全相同的select语句时可能看到不⼀样的结果。
3. Repeatable Read(可重复读):mysql默认事物隔离级别,在同⼀事物中多次读取同样的数据结果是⼀样的,解决了不可重复读的问题,此级别会出现幻读的问题,幻读:当⽤户读取某⼀范围的数据⾏时,另⼀个事务⼜在该范围内插⼊了新⾏,当⽤户再读取该范围的数据⾏时,会发现有新的“幻影” ⾏。
4. Serializable(串⾏化):最⾼的事物隔离级别,串⾏化强制事物排序阻塞,避免事物冲突,解决了上述所有的问题,它使⽤了共享锁,执⾏效率低下,会导致⼤量的超时和锁切换竞争现象,实际开发应⽤很少。
数据库事务并发可能出现的问题:
脏读:在隔离级别读未提交中可能会出现,⼀个事务读取另外⼀个事务还没有提交的数据叫脏读,事物A读取了事物B更新的事物,事物B没有commit并且回滚,此时就事物A产⽣脏读,应⽤也没保证数据的正确性。新建表,就以财务转账为例⼦来演⽰出现的问题
设定mysql事物隔离级别
mysql默认的事物隔离级别为可重复读(Repeatable Read
),可使⽤SELECT @@tx_isolation查看。
查看mysql默认事物隔离级别
设定事物隔离级别,mysql存储引擎InnoDB⽀持事物,MyISAM不⽀持事物,当前mysql默认存储引擎是InnoDB。这⾥,我们开启两个mysql的session会话,把隔离级别都设定为读未提交:
create table account(id int(11) primary key auto_increment,name varchar(16),money float);
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE];
设定隔离级别为读未提交
脏读
向表account中插⼊⼀条记录,zhangsan⾦额为1000
记录
开启⼀个事物A,在该事物中把zhangsan的⾦额扣除300,暂时不提交和回滚:
事物A
另开⼀个事物B,在事物B中查看zhangsan当前⾦额数:
事物B
此时在事物B中读取到的数据就为脏数据,事物B读取到了事物A未提交(commit)的数据,当事物A回滚(rollback)时,事物B 之前读取到的数据会给应⽤带来数据错误。session数据错误是什么意思
不可重复读:在隔离级别读已提交中可能会出现的问题,事物能读取其他事物对同⼀数据的更改。事务 A 多次读取同⼀数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同⼀数据时,结果不⼀致。
设定mysql事物隔离级别为读已提交
1begin;2update account set money=money-300 where id=1;
1begin;2select * from account where id=1;
不可重复读
在A中开启⼀个事物A,第⼀次读取到zhangsan的⾦额数为1000:
事物A
然后另外开启⼀个事物B,添加⾦额200,并且提交事物:
事物B
在事物B提交之后再在事物A中读取zhangsan的⾦额数:
事物A
可以看到事物A读取到的数据与之前读取到的不⼀致,此时就产⽣了不可重复读的现象。
set session transaction isolation level read committed;
1begin;2select * from account where id=1;
1
begin;2update account set money=money+200 where id=1;3commit;
幻读:在隔离级别可重复读中可能出现的问题,幻读是针对按范围读取多条数据的现象。同⼀事务A多次查询,若另⼀事务B只是update,则A事务多次查询结果相同;若B事务insert/delete数据,则A事务多次查询就会发现新增或缺少数据,出现幻读。设定mysql事物隔离级别为可重复读
幻读
在事物A中查表数据:
事物A
然后在B中开启新事物,插⼊⼀条数据,并提交事物:
事物B
接下来我们在事物A中查询,发现查询不到第5条记录,但是我们在A中插⼊id为5的记录时会出问题:
事物A,插⼊数据
此时就产⽣了幻读现象,在事物A中查询不到数据,却被告知数据已经存在,解决幻读⼀般需要锁表。
综上,四种隔离级别分别会出现的问题,读未提交未解决任何问题,串⾏化避免了所有的问题,mysql默认可重复读:
set session transaction isolation level repeatable read;
1
begin;2insert into account value(5,'l5',500);3commit;
√表⽰存在问题
MySql
mysql默认存储引擎是InnoDB,InnoDB与Myisam相⽐,InnoDB⽀持事物,⽀持多种锁机制,有⾏锁和表锁,Myisam只⽀持表锁,且不⽀持事物。
上述详细的介绍了mysql事物隔离级别,那么,mysql事物隔离是怎么实现的呢?底层原理是什么?
锁是⽤来实现数据库事物隔离级别的重要机制,mysql提供了多种锁机制,有共享锁、排他锁、意向共享锁、意向排他锁等,其中共享锁和排他锁都是⾏锁,意向锁是表锁,意向锁系统控制,⼈为操作不了。
数据库实现事务隔离的⽅式有两种:
1. ⼀种是在读取数据前,对其加锁,阻⽌其他事务对数据进⾏修改,简称为LBCC。
2. 另⼀种是不⽤加任何锁,通过⼀定机制⽣成⼀个数据请求时间点的⼀致性数据快照(Snapshot),并⽤这个快照来提供⼀定级别(语
句级或事务级)的⼀致性读取,简称MVCC。
锁的概念
在mysql中,锁分为表锁、⾏锁,⾏级锁有共享锁、排他锁。表锁有意向锁,意向共享锁和意向排他锁。
1. 共享锁,⼜称为S锁、读锁,顾名思义,共享锁是多个事务对于同⼀数据可以共享⼀把锁,都能访问到数据,但是只能读不能修改。普
通查询不会加任何锁,⼿动加共享锁使⽤select ... lock in share mode语句。
2. 排他锁,⼜称为X锁、写锁,排他锁两个事物不能共存。如⼀个事务获取了⼀个数据⾏的排他锁,其他事务就不能再获取该⾏的其他
锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就⾏读取和修改,所以排他锁会阻塞其他事物的读操作和写操作,直到释放排他锁。在 InnoDB中,update,delete,insert都会⾃动给涉及到的数据加上排他锁,select查询语句可使⽤select ...for update加排他锁,事物结束或者rollback/commit就会释放锁。
3. 意向共享锁(IS):事务打算给数据⾏加⾏共享锁,事务在给⼀个数据⾏加共享锁前必须先取得该表的IS锁,反之亦然。
4. 意向排他锁(IX):事务打算给数据⾏加⾏排他锁,事务在给⼀个数据⾏加排他锁前必须先取得该表的IX锁,反之亦然。意向共享锁
和意向排他锁都是mysql⾃⾝管理,⼈为⼲预不了。
在可重复读中,幻读是通过什么⽅式解决的?
innoDB存储引擎的锁的算法有三种:
1. Record lock:单个⾏记录上的锁
2. Gap lock:gap锁,间隙锁,锁定⼀个范围,不包括记录本⾝
3. Next-key lock:record+gap 锁定⼀个范围,包含记录本⾝
Gap锁设计的⽬的是为了阻⽌多个事务将记录插⼊到同⼀范围内,⽽这会导致幻读问题的产⽣。原理是对⾏数据操作时,gap锁会对相邻范围的⾏数据加锁,阻塞,直到操作完成,针对的是⾮唯⼀性索引数据。如果是有索引的数据则会使⽤recored lock⾏锁,相对来说锁的范围较⼩,阻塞程度⼩。
为什么要存在意向锁?
innodb的意向锁主要⽤户多粒度的锁并存的情况。⽐如事务A要在⼀个表上加S锁,如果表中的⼀⾏已被事务B加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐⾏检查锁标志的开销将很⼤,系统的性能将会受到影响。举个例⼦,如果表中记录1亿,事务A把其中有⼏条记录上了⾏锁了,这时事务B需要给这个表加表级锁,如果没有意向锁的话,那就要去表中查这⼀亿条记录是否上锁了。如果存在意向锁,那么假如事务A在更新⼀条记录之前,先加意向锁,再加X锁,事务B先检查该表上是否存在意向锁,存在的意向锁是否与⾃⼰准备加的锁冲突,如果有冲突,则等待直到事务A释放,⽽⽆须逐条记录去检测。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。