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