美文网首页
mysql锁学习笔记!

mysql锁学习笔记!

作者: DragonersLi | 来源:发表于2021-08-27 16:14 被阅读0次

按照锁粒度进行划分:行锁、页锁、表锁
每个层级的锁数量是有限制的,因为锁会占用内存空间,锁空间的大小是有限的。当某个层级的锁数量超过了这个层级的阈值时,就会进行锁升级。锁升级就是用更大粒度的锁替代多个更小粒度的锁

行锁就是按照行的粒度对数据进行锁定。
锁定力度小,发生锁冲突概率低,可以实现的并发度高,但是对于锁的开销比较大,加锁会比较慢,容易出现死锁情况。

页锁就是在页的粒度上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行记录。
页锁的开销介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。


表锁就是对数据表进行锁定,锁定粒度很大,同时发生锁冲突的概率也会较高,
数据访问的并发度低。不过好处在于对锁的使用开销小,加锁会很快。
image.png

从数据库管理的角度对锁进行划分:共享锁(读锁)排它锁(写锁)意向锁(Intent Lock)
共享锁也叫读锁或 S 锁,共享锁锁定的资源可以被其他用户读取,但不能修改。未释放只能select,不能insert,update,delete,会报错,其它用户增删改会一直等待直至该用户解锁。这样可以保证数据在读取时不被修改。
排它锁也叫独占锁、写锁或 X 锁。排它锁锁定的数据只允许进行锁定操作的事务使用,其他事务无法对已锁定的数据进行查询或修改。对数据库增删改时也会自动使用排它锁,防止其他事务对该数据行进行操作。
意向锁简单来说就是给更大一级别的空间示意里面是否已经上过锁。

show status like 'innodb_row_lock%'; #查看行锁情况
 unlock table #解除表锁

表读锁允许不同事务之前共享加锁读取,但不允许其它事务修改或者加入排他锁。如果有修改必须等待一个事务提交完成,才可以执行,容易出现死锁

#客户端1
lock table test read;  #读锁
 select * from test; #查询√
insert、update、delete该表都会报错: 
>1099 - Table 'test' was locked with a READ lock and can't be updated #报错内容

select、insert、update、delete其它表都会报错:
>1100 - Table 'test2' was not locked with LOCK TABLES #报错内容


 
#客户端2只可查询 
select * from test;查询√  
insert、update、delete该表;#增删改会一直等待,直到客户端1解锁

 select、insert、update、delete其它表都ok


#行读锁
#客户端1:
 select * from test where id=1 lock in share mode  
其它事务可以对该表加读锁,但不可加写锁。如果加了读锁要更新数据则报错或等待。

写锁不允许其它事务增加共享或排他锁读取。修改是惟一的,必须等待前一个事务 commit

#客户端1
lock table write;加写锁
select、insert、update、delete该表都可以,但是对其它表增删改查会报错:
> 1100 - Table 'user' was not locked with LOCK TABLES


#客户端2
select、insert、update、delete该表未释放不能读写,会一直等待:
select、insert、update、delete其它表都ok

从程序员的角度对进行划分:悲观锁乐观锁
乐观锁和悲观锁并不是锁,而是锁的设计思想。
乐观锁(Optimistic Locking)认为对同一数据的并发操作不会总发生,属于小概率事件,不用每次都对数据上锁,也就是不采用数据库自身的锁机制,而是通过程序来实现。在程序上,我们可以采用版本号机制或者时间戳机制实现。
乐观锁的版本号机制乐观锁的时间戳机制
乐观锁就是程序员自己控制数据并发操作的权限,基本是通过给数据行增加一个戳(版本号或者时间戳),从而证明当前拿到的数据是否最新。
悲观锁(Pessimistic Locking)也是一种思想,对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性。

image.png
乐观锁适合读操作多的场景,相对来说写的操作比较少。
它的优点在于程序实现,不存在死锁问题,不过适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作。
悲观锁适合写操作多的场景,因为写的操作具有排它性。
采用悲观锁的方式,可以在数据库层面阻止其他事务对该数据的操作权限,防止读 - 写和写 - 写的冲突。

死锁
死锁就是多个事务(如果是在程序层面就是多个进程)在执行过程中,
因为竞争某个相同的资源而造成阻塞的现象。发生死锁,往往是因为在事务中,锁的获取是逐步进行的。

如果事务涉及多个表,操作比较复杂,那么可以尽量一次锁定所有的资源,而不是逐步来获取,这样可以减少死锁发生的概率;
如果事务需要更新数据表中的大部分数据,数据表又比较大,这时可以采用锁升级的方式,比如将行级锁升级为表级锁,从而减少死锁产生的概率;
不同事务并发读写多张数据表,可以约定访问表的顺序,采用相同的顺序降低死锁发生的概率。
采用乐观锁的方式不会发生死锁;
MySQL MyISAM 存储引擎中也不会出现死锁,这是因为 MyISAM 总是一次性获得全部的锁,这样的话要么全部满足可以执行,要么就需要全部等待。
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,
在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁
在InnoDB中有三种行锁的方式:
1)记录锁:针对单个行记录添加锁。
2)间隙锁(Gap Locking):可以帮我们锁住一个范围(索引之间的空隙),但不包括记录本身。采用间隙锁的方式可以防止幻读情况的产生。
3)Next-Key锁:帮我们锁住一个范围,同时锁定记录本身,相当于间隙锁+记录锁,可以解决幻读的问题
image.png

相关文章

网友评论

      本文标题:mysql锁学习笔记!

      本文链接:https://www.haomeiwen.com/subject/nifarxtx.html