我们知道,数据也是一种供许多用户共享访问的资源。如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素。从这一角度来说,锁对于数据库而言就显得尤为重要。本文将带领大家一起深入领略Mysql锁的各种风采。

表锁

表级锁是mysql锁中粒度最大的一种锁,表示当前的操作对整张表加锁,资源开销比行锁少,不会出现死锁的情况,但是发生锁冲突的概率很大。

该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。

所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。

表锁被大部分的mysql引擎支持,MyISAM和InnoDB都支持表级锁。

MyISAM只是支持表锁,因此性能相对Innodb来说相对降低,而Innodb也支持表锁,但是默认的行锁,而且只有在查询或者其他SQL语句通过索引才会使用行锁。

行锁

行锁的是mysql锁中粒度最小的一种锁,因为锁的粒度很小,所以发生资源争抢的概率也最小,并发性能最大,但是也会造成死锁,每次加锁和释放锁的开销也会变大。目前主要是Innodb使用行锁,Innodb也是mysql在5.5.5版本之后默认使用的存储引擎。

行锁按照使用方式也氛围共享锁(S锁或者读锁)和排它锁(X锁或者写锁)

共享锁(S锁,读锁)

使用说明:若事务A对数据对象1加上S锁,则事务A可以读数据对象1但不能修改,其他事务只能再对数据对象1加S锁,而不能加X锁,直到事务A释放数据对象1上的S锁。这保证了其他事务可以读数据对象1,但在事务A释放数据对象1上的S锁之前不能对数据对象1做任何修改。

用法:

select ... lock in share mode;----共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。复制代码

排它锁(X锁,写锁)

使用说明:若事务A对数据对象1加上X锁,事务A可以读数据对象1也可以修改数据对象1,其他事务不能再对数据对象1加任何锁,直到事务A释放数据对象1上的锁。这保证了其他事务在事务A释放数据对象1上的锁之前不能再读取和修改数据对象1。

select ... for update----排他锁就是不能与其他所并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁复制代码

意向共享锁(IS)和意向排它锁(IX)

释义:

意向共享锁(IS):事务想要在获得表中某些记录的共享锁,需要在表上先加意向共享锁。意向互斥锁(IX):事务想要在获得表中某些记录的互斥锁,需要在表上先加意向互斥锁。复制代码

意向共享锁和意向排它锁总称为意向锁。意向锁的出现是为了支持Innodb支持多粒度锁。

首先,意向锁是表级别锁。

理由:当我们需要给一个加表锁的时候,我们需要根据意向锁去判断表中有没有数据行被锁定,以确定是否能加成功。如果意向锁是行锁,那么我们就得遍历表中所有数据行来判断。如果意向锁是表锁,则我们直接判断一次就知道表中是否有数据行被锁定了。所以说将意向锁设置成表级别的锁的性能比行锁高的多。

有了意向锁之后,前面例子中的事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的写锁时就会失败,因为表上有意向排他锁之后事务B申请表的写锁时会被阻塞。

所以,意向锁的作用就是:

当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。

乐观锁

乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。

通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。也就是先查询出那条记录,获取出version字段,如果要对那条记录进行操作(更新),则先判断此刻version的值是否与刚刚查询出来时的version的值相等,如果相等,则说明这段期间,没有其他程序对其进行操作,则可以执行更新,将version字段的值加1;如果更新时发现此刻的version值与刚刚获取出来的version的值不相等,则说明这段期间已经有其他程序对其进行操作了,则不进行更新操作。

使用实例:

1. SELECT data AS old_data, version AS old_version FROM …;2. 根据获取的数据进行业务操作,得到new_data和new_version3. UPDATE SET data = new_data, version = new_version WHERE version = old_versionif (updated row > 0) {// 乐观锁获取成功,操作完成} else {// 乐观锁获取失败,回滚并重试}复制代码

优点:从上面的例子可以看出,乐观锁机制避免了长事务中的数据库加锁开销,大大提升了大并发量下的系统整体性能表现。
缺点:乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。在系统设计阶段,应该充分考虑到这些情况出现的可能性,并进行相应调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。
总结:读用乐观锁,写用悲观锁。

悲观锁

悲观锁介绍(引自百科):
悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)

悲观锁的实现:首先实现悲观锁时,我们必须先使用set autocommit=0; 关闭mysql的autoCommit属性。因为我们查询出数据之后就要将该数据锁定。

关闭自动提交后,我们需要手动开启事务。

//1.开始事务begin; 或者 start transaction;//2.查询出商品信息,然后通过for update锁定数据防止其他事务修改select status from t_goods where id=1 for update;//3.根据商品信息生成订单insert into t_orders (id,goods_id) values (null,1);//4.修改商品status为2update t_goods set status=2;//4.提交事务commit; --执行完毕,提交事务复制代码

上述就实现了悲观锁,悲观锁就是悲观主义者,它会认为我们在事务A中操作数据1的时候,一定会有事务B来修改数据1,所以,在第2步我们将数据查询出来后直接加上排它锁(X)锁,防止别的事务来修改事务1,直到我们commit后,才释放了排它锁。

优点:保证了数据处理时的安全性。缺点:加锁造成了开销增加,并且增加了死锁的机会。降低了并发性。

乐观锁更新有可能会失败,甚至是更新几次都失败,这是有风险的。所以如果写入居多,对吞吐要求不高,可使用悲观锁。

下面三种锁都是innodb的行锁,前面我们说过行锁是基于索引实现的,一旦加锁操作没有操作在索引上,就会退化成表锁。

间隙锁(Next-Key锁)

间隙锁,作用于非唯一索引上,主要目的,就是为了防止其他事务在间隔中插入数据,以导致“不可重复读”。

如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。

如图:(1,4),(4,7),(7,11),(11,∞)即为间隙锁要锁定的位置。

举例说明:

SELECT * FROM table WHERE id = 8 FOR UPDATE;----此时,(7,11)就会被锁定SELECT * FROM table WHERE id BETWEN 2 AND 5 FOR UPDATE;----此时,(1,4)和(4,7)就会被锁定复制代码

记录锁

记录锁,它封锁索引记录,作用于唯一索引上,如下图所示:

select * from t where id=4 for update;它会在id=4的索引记录上加锁,以阻止其他事务插入,更新,删除id=1的这一行。需要说明的是:select * from t where id=4;则是快照读(SnapShot Read),它并不加锁,不影响其他事务操作该数据。复制代码

临键锁

临键锁,作用于非唯一索引上,是记录锁与间隙锁的组合,如下图所示:

它的封锁范围,既包含索引记录,又包含索引之前的区间,即(负无穷大,1],(2,4],(5,7],(8,11],(12,无穷大]。

在事务A中执行:

UPDATE table SET name = 'javaHuang' WHERE age = 4;SELECT * FROM table WHERE age = 4 FOR UPDATE;这两个语句都会锁定(2,4],(4,7)这两个区间。即, InnoDB 会获取该记录行的 临键锁 ,并同时获取该记录行下一个区间的间隙锁。复制代码

临键锁的出现是为了innodb在rr隔离级别下,解决幻读问题(如何解决幻读问题,后续会出文章详细解答,也可以关注公众号【ToBeTopJavaer】,查看)。

如果把事务的隔离级别降级为RC,临键锁则也会失效。

死锁

释义:死锁是指两个或两个以上事务在执行过程中因争抢锁资源而造成的互相等待的现象

上图所示,即为死锁产生的常规情景。

那么如何解决死锁?

1.等待事务超时,主动回滚。

2.进行死锁检查,主动回滚某条事务,让别的事务能继续走下去。

下面提供一种方法,解决死锁的状态:

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;--查看正在被锁的事务复制代码
kill trx_mysql_thread_id;--(上图trx_mysql_thread_id列的值)复制代码

死锁是一个很复杂的话题,此处只能简而言之,后续会写一篇专门讲解死锁的文章。

总结

通过本文,大致了解了mysql大部分锁的功能,作用,实现以及解决方法,我想做为了一个java开发工程师,了解到这个程度应该已经够了,毕竟我们不是DBA,不然了解太深,抢了DBA的饭碗可就不太好了,开个玩笑,毕竟学无止境。

怒求一波赞

能坚持看到这儿的都是努力学习的人,我们相信,努力奋斗终将会使我们过上自己想要的生活。

我会努力更新原创干货,也会收集一些精品文章,供大家日常学习。不论如何,如果大家觉得在我这儿能学到点东西,在这儿厚着脸皮的向大家求个赞,求个关注,求个分享。我一定不会辜负大家,为大家的学习之路添加更多精彩的文章。

创作不易,坚持不易,大家的支持是我最大的动力,再次谢谢大家。

mysql 释放行锁_《深入精通Mysql(三)》深入底层Mysql各种锁机制(面试必问)...相关推荐

  1. MySQL代做题_转行数据分析第三篇:mysql查询入门练习题

    这篇练习题是我在学sql入门的时候做的,应该算是在网上能找到的习题里最基础的一篇,非常适合新手练习,如果你接触sql不超过半个月,建议可以看一下<sql必知必会>或<mysql必知必 ...

  2. MySQL数据库,从入门到精通:第七篇——MySQL单行函数应用

    MySQL数据库,从入门到精通:第七篇--MySQL单行函数应用 第七篇_单行函数 1. 函数的理解 1.1 什么是函数 1.2 不同DBMS函数的差异 2. 数值函数 2.1 基本函数 2.3 三角 ...

  3. MySQL数据库,从入门到精通:第四篇——MySQL中常用的运算符及其用法

    MySQl学习(MySQL数据库,从入门到精通:第四篇--MySQL中常用的运算符及其用法 第四篇_MySQL中常用的运算符及其用法运算符 1. 算术运算符 1.加法与减法运算符 2.乘法与除法运算符 ...

  4. 互联网公司面试必问的mysql题目(上)

    又到了招聘的旺季,被要求准备些社招.校招的题库. 介绍:MySQL是一个关系型数据库管理系统,目前属于 Oracle 旗下产品.虽然单机性能比不上oracle,但免费开源,单机成本低且借助于分布式集群 ...

  5. 互联网公司面试必问的mysql题目(下)

    这是mysql系列的下篇,上篇文章地址我附在文末. 什么是数据库索引?索引有哪几种类型?什么是最左前缀原则?索引算法有哪些?有什么区别? 索引是对数据库表中一列或多列的值进行排序的一种结构.一个非常恰 ...

  6. 面试必问:一文弄懂MySQL数据库索引之底层数据结构和索引类型

    面试必问:一文弄懂MySQL数据库索引之底层数据结构和索引类型 前言 一.索引 1.1作用 1.2特点 1.3使用 1.3.1创建索引 1.3.2删除索引 1.3.3查看表中的索引 1.3.4查看SQ ...

  7. 线程同步有几种方法_架构师面试必问的多线程状态切换及常用方法

    架构师面试必问的多线程状态切换及常用方法 一.问题背景 Java架构师面试中,多线程状态切换及常用方法几乎是必问的,要掌握创建多线程的方式和方法. 二.创建多线程的几种方式 2.1方式一继承Threa ...

  8. mysql x key 组合_技本功丨浅谈MySQL的七种锁

    作者:宋丹琪(花名:三思)袋鼠云云服务部DBA团队 数据库工程师 时常会有开发的同学突然紧张兮兮地找我, 然后丢给我一个代码层面的 CannotAcquireLockException的报错, 一脸无 ...

  9. 为什么不用mysql版本号加锁_面试必问的Mysql事务和锁,你真的了解吗?

    前言 本文内容 事务的定义和作用,隔离级别 MVCC 是什么,快照读和加锁读 锁分类,行锁,意向锁,怎么查看 Mysql 锁的信息 悲观锁和乐观锁的使用场景 Mysql 的版本为 8.0.17. 事务 ...

最新文章

  1. JSTL 格式化 BigDecimal对象
  2. tomcat启动前端项目
  3. msm8909相关事宜
  4. [html] 说说你对abbr标签的理解,它有什么含义?
  5. android怎么升级版本5.0,一加手机怎么升级安卓5.0系统
  6. Software--WCF
  7. 【教程搬运】廖雪峰Git的使用教程(二)
  8. 春招面试的总结与自我反省
  9. sym4 matlab,使用MATLAB工具wfusimg函数进行图像的融合
  10. 高德地图开发 —— 获取高德地图开发的 key
  11. 设备电容老化危害大,出厂测试可别轻视它!
  12. Web系统测试中的重点
  13. js校验图片是否加载成功或失败
  14. uni-app使用 (从下载到项目启动 流程 踩坑)
  15. c语言中延时函数delay1,delay什么意思_delay.h这一段是什么意思
  16. 如何成功软件开发外包
  17. 【记录一次nginx转发 80端口无效】
  18. 支付宝怎么做风险控制?
  19. 滚石30年演唱会全纪录
  20. openpyxl模块介绍 ——读取excel表格

热门文章

  1. deepin Linux vscode 配置C++环境
  2. React.js 小书 Lesson24 - PropTypes 和组件参数验证
  3. 解决Sql Server服务远程过程调用失败
  4. UVALive 3958 Weird Numbers (负进制数)
  5. img标签中alt和title属性的正确使用
  6. MeteoInfoLab脚本示例:多Y轴图
  7. 关于在asp.net中的调试
  8. struts2的通配符和动态方法调用
  9. SpringBoot,用200行代码完成一个一二级分布式缓存
  10. 百度地图label样式修正