MySQL数据库锁机制之MyISAM引擎表锁和InnoDB行锁详解

MySQL中的锁概念

Mysql中不一样的存储引擎支持不一样的锁机制。好比MyISAM和MEMORY存储引擎采用的表级锁,BDB采用的是页面锁,也支持表级锁,InnoDB存储引擎既支持行级锁,也支持表级锁,默认状况下采用行级锁。java

Mysql3中锁特性以下:mysql

表级锁:开销小,加锁块;不会出现死锁,锁定粒度大,发生锁冲突的几率最高,并发度最低。面试

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发性也最高。spring

页面锁:开销和加锁界于表锁和行锁之间,会出现死锁;锁定粒度界与表锁和行锁之间,并发通常。sql

MyISAM表索

1.查询表级锁争用状况

经过检查table_locks_waited和table_locks_immediate状态变量分析系统上表锁争夺状况数据库


table_locks_waited锁定等待时间越长,则说明存在较严重的表级别锁争用状况。bash

2.锁模式

mysql的表锁有两种模式:表共享读锁(table read lock)和表独占写锁(table write lock)

说明 1.myISAM表的读操做,不会阻塞其余用户对同一个表的读请求,但会阻塞对同一个表的写请求。
2.myISAM表的写操做,会阻塞其余用户对同一个表的读和写操做。
3.myISAM表的读、写操做之间、以及写操做之间是串行的。
实例以下,打开了两个会话,当t3处于读锁定时候,会话二能够检索t3数据。当t3处于写锁定时候,会话二只有等到解锁后,才能显示数据(能够对比检索时间)。

3.加表锁

MyISAM在执行查询前,会自动执行表的加锁、解锁操做,通常状况下不须要用户手动加、解锁,可是有的时候也须要显示加锁。
好比:检索某一个时刻t1,t2表中数据数量。
经常使用代码以下:
select count(t1.id1) as 'sum' from t1;
select count(t2.id1) as 'sum' from t2;
其实这是不正确的,颇有可能当你在检索t1的那个时间点,t2的数据已经发生了变化,也就是说你检查出的t1和t2数据结果不是在同一个时间点上。
正确的作法是:
lock table t1 read, t2 read;select count(t1.id1) as 'sum' from t1;select count(t2.id1) as 'sum' from t2;unlock tables;复制代码

固然也可以使用union,这样写:
SELECT   COUNT(t1.`id1`) AS dadasum,'t1' AS tablenameFROM  t1UNIONALL SELECT   COUNT(t2.`id1`)AS dadasum ,'t2' AS tablenameFROM  t2 ;复制代码
注意事项
1.在锁定表时候,若是加上关键字local,知足myISAM表的并发插入问题。eg: lock table t3 read local;
2.使用locak tables 给表加锁时候,必须同时给全部涉及到的表加锁,由于加锁以后,当前会话,就不能操做没有加锁的表。

4.并发插入问题

myISAM存储引擎有一个系统变量,concurrent_insert,专门用来控制并发插入行为的,值能够为0,1,2.
concurrent_insert为0时候,不容许插入
concurrent_insert为1时候,若是mysql没有空洞(中间没有被删除的行),myISAM运行一个进程读表的时候,另外一个进程从表尾插入记录,这也是mysql默认设置。
concurrent_insert为2时候,不管MyISAM表中有没有空洞,都容许在表尾并行的插入。

5.myISAM锁调度问题

MyISAM存储引擎的读锁和写锁是互斥的,读写操做室串行的,那么若是读写两个进程同时请求同一张表,Mysql将会使写进程先得到锁。不只仅如此,即便读请求先到达锁等待队列,写锁后到达,写锁也会先执行。由于mysql由于写请求比读请求更加剧要。这也正是MyISAM不适合含有大量更新操做和查询操做应用的缘由。
调节办法:
1)经过指定启动参数low-priority-updates,使MyISAM引擎默认给与读请求优先的权限
2)经过执行set low_PRIORITY_UPDATES=1,下降更新请求的优先级。
3)指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性。

InnoDB锁

1.InnoDB与MyISAM最大不一样有两点:

1).支持事务
2).采用行级锁

2.查看InnoDB行锁争用状况


3.innodb行锁模式以及加锁方法

innoDB实现了以先两种类型的行锁:
共享锁(S):容许一个事务去读一行,阻止其余事务获取相同数据集的排他锁。
排他锁(X):容许得到排他锁的事务更新数据,阻止其余事务取得相同数据集的共享读锁和排他写锁。
先两种意向表锁:
意向同享锁
意向排他锁


若是一个事务请求的锁模式与当前的锁模式兼容,innodb就将请求的锁授予该事务;反之,若是二者不兼容,该事务就要等待锁释放。意向锁是Innodb自动加的,不须要用户干预。对于UPDATE、DELETE、INSERT语句,Innodb会自动给涉及的数据集加排他锁(X);对于普通SELECT语句,Innodb不会加任何锁。

显示添加锁
共享锁(S) : SELECT * FROM table_name WHERE .... LOCK IN SHARE MODE
排他锁(X): SELECT * FROM table_name WHERE .... FOR UPDATE.
使用select ... in share mode获取共享锁,主要用在须要数据依存关系时,确认某行记录是否存在,并确保没有人对这个记录进行update或者delete。

4.InnoDB行锁实现方式

InnoDB行锁是经过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不一样,后者是经过再数据块中,对相应数据行加锁来实现的。InnoDB这种行锁实现特色意味着:只有经过索引条件检索数据,innoDB才使用行级锁,不然InnoDB将使用表锁,在实际开发中应当注意。
实例一:
创建t1表以下:
CREATE TABLE `t1` (  `id1` int(5) DEFAULT NULL,  `id2` int(3) unsigned zerofill NOT NULL DEFAULT '000') ENGINE=InnoDB DEFAULT CHARSET=utf8复制代码
<span style="font-size:18px;">insert into t1 valuses(1,1),(2,2);</span>
复制代码


由于没有建立索引,当给第一个会话添加索引时候,其实添加的是表索引,而非行索引,由于第二会话在查询其余信息时候,一直处于等待状态,最后超时,直到第一个会话事务提交后,方可查询。(须要先设置 set autocommit=0)
实例二:
修改上面t1表中数据,数据以下

给id1添加索引ALTER TABLE t1 ADD INDEX id1(id1);


有此能够看出此时,mysql使用的是行索引。
可是还有一个须要咱们注意

很明显两个会话查询的不是同一行记录,为何会话2仍然须要等待会话1提交以后才能查询呢?仍是由于Mysql行锁是针对索引加的锁,不是针对记录加的锁,索引虽然访问不一样的记录,可是他们的索引相同,是会出现冲突的,在设计数据库时候须要注意这一点。上面只有将字段id2,也添加上索引才能解决冲突问题。这也是mysql效率低的一个缘由。

工做一到五年的java 开发工程师朋友能够加入咱们Java架构交流群:760940986 群内提供 高可用,高并发,spring源码,mybatis源码,JVM,大数据,Netty等多个技术知识的架构视频资料 还有大把大牛在群内交流以及解答面试指导,问题答疑~~要进来和大牛交流学习提高提高本身吗~~~~ 
mybatis

加群能够获取一份人生职业规划思惟导图以及进阶架构师必备视频资料~架构

相关文章
相关标签/搜索