1、分类
MySQL的锁机制不一样的存储引擎支持不一样的锁机制,分为表级锁、行级锁、页面锁。MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认状况下是采用行级锁mysql
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的几率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常 算法
2、表级锁
MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。 sql
对MyISAM表的读操做,不会阻塞其余用户对同一表的读请求,但会阻塞对同一表的写请求;对 MyISAM表的写操做,则会阻塞其余用户对同一表的读和写操做。数据库
MyISAM在执行查询语句(SELECT)前,会自动给涉及的全部表加读锁,在执行更新操做 (UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不须要用户干预,所以,用户通常不须要直接用LOCK TABLE命令给MyISAM表显式加锁。微信
3、行级锁
InnoDB与MyISAM的最大不一样有两点:一是支持事务(TRANSACTION);二是采用了行级锁。架构
行级锁也支持读锁和写锁两类。并发
一、如何加锁?
mysql InnoDB引擎默认的修改数据语句:update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,若是加排他锁可使用select …for update语句,加共享锁可使用select … lock in share mode语句。因此加过排他锁的数据行在其余事务种是不能修改数据的,也不能经过for update和lock in share mode锁的方式查询数据,但能够直接经过select …from…查询数据,由于普通查询没有任何锁机制。app
二、实现原理
InnoDB行锁是经过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不一样,后者是经过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特色意味着:只有经过索引条件检索数据,并请求共享或排他锁时,InnoDB才使用行级锁,不然,InnoDB将使用表锁! 高并发
四、锁的算法
record lock:单个记录的锁。性能
gap lock:间隙锁,锁定一个范围,不包括记录自己
next-key lock:gap lock+record lock
默认隔离级别(可重复读)下,默认加的是next-key lock(为了解决幻读问题),当索引中含有惟一属性时(惟一索引,主键索引),会降级为record lock。
在读已提交隔离级别下,加的是record lock
一、例1
如今表z,有a,b两列,a是主键,全表只有一个主键索引。如今记录以下:(1,1)(3,1)(5,3)(7,6)(10,8)
select * from z where b=3 for update
由于b没有索引,因此走得是全表扫描。有由于加锁是经过对索引加锁实现,由于没有走索引,全部会锁整个表,也就是表锁
二、例2
如今表z,有a,b两列,a是主键索引,b创建辅助索引。如今记录以下:(1,1)(3,1)(5,3)(7,6)(10,8)
select * from z where a=3 for update
主键索引加的锁是record lock,对记录(3,1)加锁
select * from z where b=3 for update
由于锁是经过对索引加锁实现的。因此这里须要对主键索引和辅助索引加锁,主键索引加的锁会由next-key锁退化成是record lock,辅助索引加的锁是next-key lock,锁定范围是(1,3)、三、(3,6)
5、select的几种类型
1、快照读
读取的是快照版本,也就是历史版本。普通的SELECT就是快照读
2、当前读
读取的是最新版本。
UPDATE、DELETE、INSERT、SELECT ... LOCK IN SHARE MODE、SELECT ... FOR UPDATE是当前读。
默认的可重复读隔离级别,使用的是快照读
读已提交使用的是当前读
3、一致性非锁定读
实现原理是经过MVCC机制实现,若是读取的行正处于update或delete中,读操做不会去等待行上X锁的释放,而是去读取行的快照数据。
MVCC,多版本并发控制技术。在 InnoDB 中,在每一行记录的后面增长两个隐藏列,记录建立版本号和删除版本号。经过版本号和行锁,从而提升数据库系统并发性能。
一致性非锁定读能够极大的提升并发性能
不一样的事务隔离级别,读取的快照版本是有差异的
读已提交隔离级别,老是读取最新的快照版本。可能会产生幻读
可重复读隔离级别,老是读取事务开始后第一次读取的快照版本。能够避免幻读的产生
4、一致性锁定读
默认配置下,采用可重复读的隔离级别,读取数据采起的是一致性非锁定读。
可是某些场景下须要对读取操做加锁来保证严格的数据一致性,这时候能够显式的对读取的记录进行加锁:
select *** for update(对读取记录加X锁)
给索引记录加锁,这种状况下跟UPDATE的加锁状况是同样的
select *** lock in share model(对读取记录加S锁)
给记录假设共享锁,这样一来的话,其它事务只能读不能修改,直到当前事务提交
做者:leon66666
出处:http://www.cnblogs.com/wangzhongqiu/
若是你以为文章不错,文末的赞 👍 又回来啦,记得给我「点赞」和「在看」哦~
本文分享自微信公众号 - JAVA高级架构(gaojijiagou)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。