1.mysql锁的概述

2.mysql的表锁及案例分析

3.mysql的行锁及案例分析

4.总结

1.mysql锁的概述

1.1锁的定义
我们先来看一下锁的定义:锁是计算机协调多个进程或者线程并发访问某一资源的机制

那么在数据库中,数据也是一种供许多用户的共享资源,如何保证数据并发访问的一致性,有效性,排他性,这也是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个主要因素,从这些角度来看,锁对数据库显得尤其重要。

我们举一个例子,淘宝购物。 假设我们到购物网站上购买一个商品,这个时候库存为数不多,多个人一起抢购,那么如何解决是你买到还是别人买到的问题?

image.png

这个时候,就需要用锁,对有限的资源进行保护,解决并发的矛盾。

1.2锁的分类

从数据操作的类型来看,锁可以分为读锁和写锁

读锁(共享锁):针对读操作,多个读操作可以同时进行而不互相影响,但是不能进行写操作。

写锁(排它锁):当前操作没有完成前,它会阻断其他写锁和读锁。

从对数据操作的颗粒度来看,锁可以分为表锁和行锁。

表锁:操作数据的时候,锁住整张表

行锁:操作数据的时候,锁住需要操作的那一行数据。

2.mysql的表锁及案例分析

表锁:mysql的表锁是MyISAM存储引擎有的锁,开销小,加锁快,无死锁,锁的粒度大,发生锁冲突的概率最高,并发量最低。

代码演示:

我们先创建一张myISAM为存储引擎的表:

CREATE TABLE `t_error_name` (
  `error_name` varchar(255) COLLATE utf8_bin DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

加读锁:

session 1session2
加读锁 image.png连接mysql
当前session可以查询该表的记录 image.png其它的session也可以读该表的记录image.png
当前session不可以查询没有read锁的表 image.png其他session可以查询或者更新未锁定的表
当前session不可以插入或者更新read锁的表 image.png其他session插入或者更新read锁住的表表会阻塞 image.png
释放锁 image.png其他session插入或者更新完成image.png

加写锁:

session1session2
当前session加写锁 image.png等待session1加锁完毕
当前session的查询,增加,修改,删除都可以执行完成对其它session,任何操作都锁定image.png
释放锁 image.pngsession2可以对该表进行操作 image.png

结论:
1.对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行对其它进程的写操作。
2.对MyISAM表的写操作(加写锁),会阻塞其它进程对同一表的读和写操作,只有当写操作释放后,才会执行其它进程的读写操作。

总而言之,读会阻塞写,不会阻塞读,写会同时阻塞读写。

所以我们可以得出,MyISAM存储引擎的读写锁调度是写优先,也就是MyISAM不适合做主表的引擎,因为一张表加上写锁后,会极大降低吞吐量,大量的请求将会被阻塞。

3.mysql的行锁及案例分析

行锁是偏向Innodb的存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率极低,并发度也最高。

Innodb和MYISAM的两个最大不同点,Innodb支持了事务,Innodb采用了行锁。

3.1事务的隔离级别

在看事务的隔离级别之前,我们要先理解以下这几个概念:

1.脏读
脏读指的是数据库读到其他事务未提交的数据,未提交就代表着这些数据可能回滚,这些可能会回滚的数据到最后可能会不存在,所以读到了不一定最终存在的数据,这就是脏读。

2.不可重复读

不可重复读指的是在同一事务内,不同时刻读到的同一批数据可能是不一样的,可能会受到其它已经完成的事务的影响,比如其他事务改了这批数据并提交了,通常针对的是UPDATE操作

3.可重复读

可重复读指的是,在一个事务内,最开始读到的数据和事务结束的任意时刻读到的同一批数据都是一致的,通常也是针对数据的update操作。

4.幻读

可重复读和不可重复读只是对于update而言的,而幻读是针对数据插入insert操作来说的,假设事务A对某些内容作了更改,还未提交,此时事务B又对事务A范围内操作的数据中,又插入了几条数据,事务A在事务快结束的时候,再去查询事务A开始操作的数据,发现会比一开始操作的时候多了几条,但这其实是事务B刚刚插入进来的,让用户感觉到了幻觉,这就叫幻读。

事务的隔离级别:

事务的隔离级别脏读不可重复读幻读
读未提交可能可能可能
读提交不可能可能可能
可重复读不可能不可能可能
串行化不可能不可能不可能

接下来我们演示一下行锁,注意,行锁是建立在索引的基础上的,如果你要查询的这个字段没有加上索引那么mysql就会默认锁住所有的行

行锁演示:

session 1session 2
设置手动提交事务image.png设置手动提交事务 image.png
更新但是不提交,没有commit image.png被阻塞 image.png
提交更新 image.png解除阻塞,更新正常 image.png

间隙锁:

当我们使用范围条件而不是相等条件检索数据,并请求共享或者排他的时候,InnoDB会将目前符合条件的所有记录的索引加锁,对于键值在条件内但是不存在的记录,叫做间隙。

InnoDB也会对这个间隙加锁,这种机制就是所谓的间隙锁。

危害:因为query在执行的过程当中通过范围查找的话,就会快速锁定这个范围内的所有索引键值,即使这个键不存在,造成锁定的时候,无法插入这个范围内的所有值,在某些场景下可能会造成很大的危害。

优化锁的建议:
1.尽可能让所有数据检索都通过索引完成,避免无索引行锁升级为表锁。
2.合理设计索引,尽量缩小锁的范围
4.尽可能减少检索条件,避免间隙锁
5.尽量控制事务大小,减少锁定资源量和时间长度
6.尽可能低级别事务隔离

4.总结
今天学习了mysql的锁机制,主要学习了行锁和表锁,以及间隙锁的危害和优化建议。


苏凌峰
73 声望38 粉丝

你的迷惑在于想得太多而书读的太少。