暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL表锁与行锁

长夜难眠 2020-07-15
538

点击蓝字

关注不迷途


背景


探究MySQL表锁与行锁的不同。


分析


在多个进程或事务访问数据时,为保证数据的一致性,我们这时候就需要锁了。


行动


那么MySQL数据库的锁又有哪些呢?有行锁、表锁、页锁等。


锁是由存储引擎实现的,所以今天就MyISAM、InnoDB存储引擎探究两种存储引擎在锁上实现的比较。


这两种存储引擎的不同大都因为它们实现了不同的锁行为导致的,MyISAM实现的是表锁,InnoDB实现的是行锁。


两种存储引擎的比较:


MyISAM:表级锁,不支持事务,不支持外键,支持全文索引,使用变量存储表行数,可以很快读出行数。


InnoDB:行级锁,支持事务,支持外键,使用聚集索引,不使用变量保存行数,需要通过全文扫描才能获取行数。


同时因为锁的不同,两者适合使用的场景的差别很大。


表锁:顾名思义,锁粒度是表,粒度大,并发度相对的就小了,同时锁冲突大,但是开销小,加锁快,无死锁。


表锁分为读锁和写锁。


#加锁
lock table tableName;
#解锁
unlock tables;
#查看锁情况
show open tables;



加读锁情况下,当前session可进行读操作,不能进行写操作也不能读写其它表。



其它session,可进行读操作,但是写操作会堵塞直到释放锁,可读写其它表。




写锁,当前session,可以读写当前表,不能读写其它表。



其它session,不能读写该表,会阻塞直到该表的锁释放,可以读写其它表。




#分析锁情况
show status like '%table%';


#产生表级锁定记录
table_locks_immediate;


#等待锁次数(高表示表级争用严重)
table_locks_waited:



行锁:锁粒度小,并发度高,发生锁冲突概率小,但是开销大,加锁慢,有死锁。


行锁的行为与事务隔离级别有关,InnoDB默认可重复读级别。解决脏读、不可重复读问题,但会出现幻读。


#关闭自动提交
set autocommit=0;
#查看锁情况
show status like '%innodb_row_lock%'
# 返回
#当前等待锁数量
innodb_row_lock_current_watis
#总等待次数
innodb_row_lock_watis
#等待锁总时间
innodb_row_lock_time
#等待最长一次所花时间
innodb_row_lock_max_time
#等待平均时间
innodb_row_lock_avg_time


需要注意的情况。


行锁变表锁:where 不走索引会导致行锁变表锁。


间隙锁:使用范围条件而不是相等条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有记录索引加锁,对于在条件范围内但并不存在的记录,叫做间隙。


InnoDB也会给这个间隙加锁。比如数据库内没有id为2的记录,更新语句更新id的范围为1-10,这时新增记录id=2的数据会被阻塞。


如何锁一行:select*from where id=2 for update;


优化建议


尽可能让所有数据检索通过索引,避免无索引行锁升级为表锁(varchar类型加引号)。


合理设计索引,尽量缩小锁范围。


尽可能较少检索条件,避免间隙锁。


尽量控制事务大小,减少锁定资源和时间长度。


尽可能低级别事务隔离。



思考


不同的情景下,应对的方法往往是不一样的。


在不需要事务,读多写少的情况下,可以选择MyISAM,因为读锁共享,而且表锁花销少,加锁快。


需要事务的,读写频繁的,需要外键约束等选择InnoDB。


MySQL5.5后默认InnoDB存储引擎,所以不知道选择什么存储引擎的时候可以使用默认存储引擎。



喜欢本篇内容顺便点个在看吧


文章转载自长夜难眠,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论