数据库锁全文及翻译
数据库锁
应用软件锁另见:Java锁。
对于一次的数据修改,我们可以大概将其分为三步:
- 获取数据
- 修改数据
- 提交修改
这里假设有A、B两个角色修改数据。
三种锁级别
表级锁
表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并发度大打折扣。
使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。
行级锁
行级锁定最大的特点就是锁定对象的颗粒度很小,由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。
由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。它实现了标准的行级锁,包括两种:共享锁(简称 s 锁)、排它锁(简称 x 锁)。
页级锁
页级锁定是MySQL中比较独特的一种锁定级别。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。
使用页级锁定的主要是BerkeleyDB存储引擎。
总结
MySQL这3种锁的特性可大致归纳如下:
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
乐观锁
对数据改动持乐观态度:认为在查询到修改的过程中,大概不会有其他人来修改数据。
实现方式
- 引入版本
给数据表添加一个version字段,每次修改提交后,版本号递增。
如A在获取数据时,数据版本是v2,那提交时执行的语句就是:
update a_table
set a_column = '*',
where version = v2
如果在中途,B修改了数据,那数据库对应数据就会变成v3,A对v2的修改就失效了,不会产生异常。
悲观锁
对数据改动持悲观态度,认为在查询修改提交期间,极有可能会有人来修改数据。
A在获取数据后,就对数据加锁,提交修改后释放。途中由于加锁,B读取时会阻塞B,读不了数据,所以数据不会被修改。
使用悲观锁可以保证不会发生异常情况,如丢失修改、重复修改等问题,相对简单易懂,能够保证资源的完整性和一致性。
但是,悲观锁的缺点也比较明显,它往往会引起死锁,降低程序的执行效率。
实现方式
主要是InnoDB存储引擎实现
排它锁(Exclusive Lock)
是一种互斥锁,也叫写锁。当一个线程获得排他锁时,会阻塞其他事务对同一行的读和写操作,只有当写锁释放后,才会执行其它事务的读写操作。
主要适用于需要进行修改的资源,如文件、数据库记录等。
select * from table_name where ... for update
从字面意思就可以知道,该语句不单单是查询,而是为了后续的修改,是要对数据加锁的。
按照 select 中 where 的字段,又可分为行锁和表锁。
- 若 where 查询索引字段,该条数据行锁(根据经验,满足同条件索引的数据也会锁定,之前听过行锁锁的是索引,不是数据);
- 查询普通字段,会导致表锁(未验证);
- 给普通字段加索引后,锁从表级降为行级(未验证);
- 修改数据,让大部分数据满足索引条件,锁会从行级升为表级;
因为索引列中目标值太多,占大部时,会走全索引扫描(未验证,这就牵扯到,目标值占多少会走全索引?),会将该字段视为普通字段,故致表锁。
对于InnoDB 在RR(MySQL默认隔离级别) 而言,对于 update、delete 和 insert 语句, 会自动给涉及数据集加排它锁(X);
对于普通 select 语句,innodb 不会加任何锁。如果想在select操作的时候加上 S锁 或者 X锁,需要我们手动加锁。
共享锁(Shared Lock)
也叫读锁,与排他锁不同的是,多个线程可以同时获得共享锁,因为共享锁是为了允许多个线程同时读取同一份资源而设计的。
select * from table_name where ... lock in share mode
对当前行加共享锁,不会阻塞其他事务对同一行的读请求,但会阻塞对同一行的写请求。只有当读锁释放后,才会执行其它事务的写操作。
主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行 update 或者 delete 操作。
但是如果当前事务也需要对该记录进行更新操作,则有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用 select…
for update 方式获得排他锁。
东西有点多,先写到这,有空再整理,下面几个锁名词来源于上文中的知乎链接。
记录锁(Record Locks)
间隙锁(Gap Locks)
临键锁(Next-Key Locks)
意向锁
插入意向锁
声明:本文使用八爪鱼rpa工具从gitee自动搬运本人原创(或摘录,会备注出处)博客,如版式错乱请评论私信,如情况紧急或久未回复请致邮 xkm.0jiejie0@qq.com 并备注原委;引用本人笔记的链接正常情况下均可访问,如打不开请查看该链接末尾的笔记标题(右击链接文本,点击 复制链接地址,在文本编辑工具粘贴查看,也可在搜索框粘贴后直接编辑然后搜索),在本人博客手动搜索该标题即可;如遇任何问题,或有更佳方案,欢迎与我沟通!
原文地址:https://blog.csdn.net/qq_41623592/article/details/142836254
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!