前段时间阿粉在公司开发的时候, 不慎导致了数据库产生了锁表的操作, 因为阿粉之前从来没有遇到过, 之前只是了解过一点, 所以导致了锁表, 于是阿粉为了解决问题, 研究了一下这一部分的内容, 于是决定把这一块的知识分享给大家.
数据库锁定机制
话说如果你只是单纯的说 "锁表", 总是让人感觉有点 Low , 而我们就直接换个比较高大上一点的名词, 锁定机制!
为了保证数据的完整, 也就是他的一致性和有效性, 所以才会让数据库出现了锁定机制, 相对其他数据库而言, MySQL 的锁机制比较简单, 其最显著的特点是不同的存储引擎支持不同的锁机制.
MyISAM 和 MEMORY 存储引擎采用的是表级锁 (table-level locking)
BDB 存储引擎采用的是页面锁 (page-level locking), 也支持表级锁
InnoDB 存储引擎既支持行级锁 (row-level locking), 也支持表级锁
我们先来瞅瞅看一下这些锁都是个什么鬼东西!
行级锁 (row-level locking)
锁的对象颗粒度很小
各大数据库中锁粒度最小的
锁定资源占用概率最小
虽然说行级锁的优点是很明显, 但是相对的弊端也因为他的优点出现了,
因为锁定的粒度比较小, 所以每次获取锁和释放锁需要做更多的内容, 带来的消耗必然也就更大了,
行级锁也是最容易发生死锁的.
并发度也最高
表级锁 (table-level locking)
和行锁相反, 粒度是最大的
逻辑简单, 对系统的负面影响比较小
获取锁和释放锁速度快
并发度最低.
弊端也有, 因为粒度比较大, 锁定资源占用概率也会很大,
页级锁 (page-level locking)
比较特殊, 介于行锁和表锁之间, 所以他的能力都是介于两者之间的, 就是
粒度比较 表级锁 > 页锁 > 行锁
而他的并发度也就是一般般了. 但是他会出现死锁, 这三个当中, 看来也就只有表锁不会出现死锁了.
我们在这里已经算是对锁机制大致有了个了解, 我们再细致的看一下
表锁
表锁实际上分为 2 种类型,
读锁定
写锁定
而这两种锁定, 又是通过其内部的队列来进行维护的,
当前读锁队列 (Current read-lock queue)
挂起的读锁队列 (Pending read-lock queue)
挂起写锁队列 (Pending write-lock queue)
当前写锁队列 (Current write-lock queue)
什么意思呢?
当前读锁的队列, 实际上就是包含了当前所有的持有读锁的线程, 这里面的内容就是按照获取锁的时间进行有序的排放,
而挂起的读锁队列中存放的则是等待获取所得线程.
那写锁大家肯定也知道是什么意思了, 就像是个 4*100 接力一样. 拿着 "棒子" 的, 就是当前读 / 写锁队列, 等着接 "棒子" 的就是 挂起的读 / 写锁队列.
行锁
MySQL 的 InnoDB 存储引擎支持行级锁, InnoDB 的行锁是通过给索引项加锁实现的.
这句话说明了什么?
说明了一件事: 只有通过索引条件检索数据时, InnoDB 才使用行锁, 否则使用表锁.
是不是感觉很诧异, 但是事实上就是这样的.
InnoDB 级别的行锁也是分成了两种
共享锁
独占锁
共享锁和独占锁 (Shared and Exclusive Locks),InnoDB 通过共享锁和独占锁两种方式实现了标准的行锁. 共享锁 (S 锁): 允许事务获得锁后去读数据, 独占锁 (X 锁): 允许事务获得锁后去更新或删除数据. 一个事务获取的共享锁 S 后, 允许其他事务获取 S 锁, 此时两个事务都持有共享锁 S, 但是不允许其他事务获取 X 锁. 如果一个事务获取的独占锁 (X), 则不允许其他事务获取 S 或者 X 锁, 必须等到该事务释放锁后才可以获取到
很多读者肯定也都了解的很深入, 肯定还有其他的, 对, 还有一种就是意向共享锁和意向独占锁.
这种意向共享锁和意向独占锁的意思就是如果我需要一个共享锁, 但是这个共享锁这时候正锁定这资源, 那我自己就可以加一个共享锁, 只能等这个共享锁释放之后, 我才能锁定, 这个锁就可以称之为意向共享锁, 同理, 独占锁也是一样的.
而他们之间的逻辑关系是这个样子的.
数据库锁表的原因
其实最简单的就是会出现在 insert,update,delete 这些操作的并发操作上, 当我们使用多个数据库连接的时候, 同时对一个表中的数据进行更新的操作的时候, 那么速度就会对应的变慢, 如果持续一段时间之后, 那么就会出现锁表的现象了.
那么都有哪些操作会导致出现锁表呢?
(1) 插入查询的语句
insert into table values select xxxx from table2
这种情况就会锁住 table2.
(2) 更新并发操作
update table1 table2 set table1.name = 'xxx' where table1.id = table2.id
这样也会导致锁表.
怎么样降低锁表的情况?
MyISAM 表锁的优化:
缩短锁定的时间: 这么说吧, 实际上最简单的就是加索引, 让你的索引利用最大化,
合理利用读写优先级: 写优先, 读其次.
Innodb 行锁的优化
加索引, 让查询走索引
学会控制事务
隔离级别不要随便设置, 根据不同情况不同选择就可以了
鸿蒙官方战略合作共建 --HarmonyOS 技术社区
来源: http://database.51cto.com/art/202110/686800.htm