我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Mysql锁机制中行锁、表锁、死锁如何实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Mysql锁机制中行锁、表锁、死锁如何实现

这篇文章主要介绍了Mysql锁机制中行锁、表锁、死锁如何实现,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

    一、Mysql锁是什么?锁有哪些类别?

    锁定义:
        同一时间同一资源只能被一个线程访问
        在数据库中,除传统的计算资源(如CPU、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。

    乐观锁用的最多的就是数据的版本记录来体现 version ,其实就是一个标识。

    例如:update test set a=a-1 where id=100 and a> 0; 对应的version就是a字段,并不一定非得要求有一个字段叫做version,要求的是有这个字段,同时当满足这个条件的时候才会触发

    Mysql锁机制中行锁、表锁、死锁如何实现

     锁的分类:
    从对数据操作的类型分法(读或写)
    读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。
    写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。

    从对数据操作的粒度分法
    表级锁:表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁(MyISAM引擎默认表级锁,也只支持表级锁)。比如说更新一张10万表数据中的一条数据,在这条update没提交事务之前,其它事务是会被排斥掉的,粒度很大。
    行级锁:行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁(基于索引实现的,所以一旦某个加锁操作没有使用索引,那么该锁就会退化为表锁)
    页级锁:页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁,一次锁定相邻的一组记录

    从并发角度的分发--实际上乐观锁和悲观锁只是一种思想
    悲观锁:对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观) ,因此,在整个数据处理过程中,将数据处于锁定状态。
    乐观锁:乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回错误信息再进行业务重试

    其他锁:
    间隙锁:在条件查询中,如:where id>100,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,间隙的目的是为了防止幻读
    意向锁:意向锁分为 intention shared lock (IS) 和 intention exclusive lock (IX),意向锁的目的就是表明有事务正在或者将要锁住某个表中的行

    二、行锁和表锁的区别

    表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单。最常使用的MYISAM与INNODB都支持表级锁定。
    特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

    行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。
    特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
    使用:InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁

    下面这个update语句,b是一般字段不是索引列的话,那么此时行级锁将改为表级锁。

    update from test set a=100 where b='100';

    现在举个实际例子操作一下,看看innnodb是怎么来用行锁的。

    当前表中数据:

    Mysql锁机制中行锁、表锁、死锁如何实现

    首先开启两个session会话窗口,然后将mysql事务级别设置成不提交级别:

    会话一窗口:

    Mysql锁机制中行锁、表锁、死锁如何实现

    会话二窗口:

    Mysql锁机制中行锁、表锁、死锁如何实现

     其中会话2的update一直都在Running中,一直到超时结束,或者会话1提交事务后才会Running结束。

    可以通过show VARIABLES like "%innodb_lock_wait_timeout%" 查询当前mysql设置的锁超时时间,默认是50秒。 

    可以通过set innodb_lock_wait_timeout = 60; 设置锁的超时时间。

    当第一个会话commit之后,第二个会话的update语句才会执行成功。这代表了innodb用了锁。

    那怎么确定是用了行锁呢?

    Mysql锁机制中行锁、表锁、死锁如何实现

    Mysql锁机制中行锁、表锁、死锁如何实现

     Mysql锁机制中行锁、表锁、死锁如何实现

     总结:会话一更新id=125的时候,给这条数据add lock了,那么在会话2中再次更新id=125的时候,这条数据是locked中的。这个lock加的是id=125这条记录。此时除了id=125这条之外的,都是可以成功的,证明这条默认加的是行锁。

    三、InnoDB死锁概念和死锁案例

    定义:当两个或以上的事务相互持有和请求锁,并形成一个循环的依赖关系,就会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。在一个事务系统中,死锁是确切存在并且是不能完全避免的。

    解决:InnoDB会自动检测事务死锁,立即回滚其中某个事务,并且返回一个错误。它根据某种机制来选择那个最简单(代价最小)的事务来进行回滚

    死锁场景一之select for update:

    产生场景:两个transaction都有两个select for update,transaction a先锁记录1,再锁记录2;而transaction b先锁记录2,再锁记录1

    写锁:for update,读锁:for my share mode show engine innodb status

    验证下死锁的场景:

    Mysql锁机制中行锁、表锁、死锁如何实现

     第一步更新会话一:

    start TRANSACTION;select * from wnn_test where a=199 for update;

    第二步更新会话二:

    start TRANSACTION;select * from wnn_test where a=101 for update;

    第三步更新会话一:

    select * from wnn_test where a=101 for update;

    第四步更新会话二;

    select * from wnn_test where a=199 for update;

    在更新到第三步和第四步的时候,已经发生了死锁。

    来看下执行的日志:

    show engine innodb status;最后一个锁的时间,锁的表,引起锁的语句。其中session1被锁 14秒(ACTIVE 14),session 2被锁了10秒(Active 10)

    Mysql锁机制中行锁、表锁、死锁如何实现

    死锁场景二之两个update

    产生场景:两个transaction都有两个update,transaction a先更新记录1,再更新记录2;而transaction b先更新记录2,再更新记录1

    Mysql锁机制中行锁、表锁、死锁如何实现

     产生日志:

    Mysql锁机制中行锁、表锁、死锁如何实现

     注意:仔细查看上面2个例子可以发现一个现象,当2条资源锁住后,再执行第三个会执行成功,但是第四个会提示死锁。在mysql5.7中,执行第三个的时候就会一直在Running状态了,本博文使用的是mysql8.0 ,其中 有这个参数 innodb_deadlock_detect 可以用于控制 InnoDB 是否执行死锁检测,当启用了死锁检测时(默认设置),InnoDB 自动执行事务的死锁检测,并且回滚一个或多个事务以解决死锁。InnoDB 尝试回滚更小的事务,事务的大小由它所插入、更新或者删除的数据行数决定。

    Mysql锁机制中行锁、表锁、死锁如何实现

     那么这个innodb_deadlock_detect参数,到底要不要启用呢?

    对于高并发的系统,当大量线程等待同一个锁时,死锁检测可能会导致性能的下降。此时,如果禁用死锁检测,而改为依靠参数 innodb_lock_wait_timeout 执行发生死锁时的事务回滚可能会更加高效。
    通常来说,应该启用死锁检测,并且在应用程序中尽量避免产生死锁,同时对死锁进行相应的处理,例如重新开始事务。

    只有在确认死锁检测影响了系统的性能,并且禁用死锁检测不会带来负面影响时,可以尝试关闭 innodb_deadlock_detect 选项。另外,如果禁用了 InnoDB 死锁检测,需要调整参数 innodb_lock_wait_timeout 的值,以满足实际的需求。

     四、程序开发过程中应该如何注意避免死锁

     锁的本质是资源相互竞争,相互等待,往往是两个(或以上)的Session加锁的顺序不一致

    如何有效避免:

    在程序中,操作多张表时,尽量以相同的顺序来访问(避免形成等待环路)

    批量操作单张表数据的时候,先对数据进行排序(避免形成等待环路) A线程 id:1 ,10 ,20按顺序加锁     B线程id:20,10,1   这种的话就容易锁。

    如果可以,大事务化成小事务,甚至不开启事务 select for update==>insert==>update = insert into update on duplicate key

    尽量使用索引访问数据,避免没有 where 条件的操作,避免锁表 有走索引是记录行锁,没走索引是表锁

    使用等值查询而不是范围查询查询数据,命中记录,避免间隙锁对并发的影响 1,10,20 等值where id in (1,10,20) 范围查询 id>1 and id<20

    避免在同一时间点运行多个对同一表进行读写的脚本,特别注意加锁且操作数据量比较大的语句;我们经常会有一些定时脚本,避免它们在同一时间点运行

    感谢你能够认真阅读完这篇文章,希望小编分享的“Mysql锁机制中行锁、表锁、死锁如何实现”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Mysql锁机制中行锁、表锁、死锁如何实现

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    Mysql锁机制中行锁、表锁、死锁如何实现

    这篇文章主要介绍了Mysql锁机制中行锁、表锁、死锁如何实现,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、Mysql锁是什么?锁有哪些类别?锁定义: 同一时间同一资
    2023-06-29

    【MySQL】说透锁机制(三)行锁升表锁如何避免? 锁表了如何排查?

    文章目录 前言哪些场景会造成行锁升表锁?如何避免?如何分析排查?查看`InnoDB_row_lock%`相关变量查看 `INFORMATION_SCHEMA`系统库 总结最后 前言 在上文我们曾小小的提到过,在索引失效的情
    2023-08-18

    MySQL的锁机制之全局锁和表锁的实现

    前言对mysql锁的总结学习,本文将围绕,加锁的概念,加锁的应用场景和优化,以php及不加锁会导致的问题这些方向进行总结学习。mysql的全局锁和表锁是本文的重编程点一、全局锁全局锁的介绍以及使用全局锁就是对整个数据库实例进行加锁。
    2023-01-15

    在Redis中如何实现分布式锁的防死锁机制?

    在Redis中实现分布式锁是一项常见的任务,可以通过Redlock算法来增强分布式锁的可靠性。
    Redis分布式2024-11-30

    Mysql行锁和表锁的实现示例

    目录行锁和表锁加索引的影响注意事项常见面试题什么是表锁和行锁?它们有什么区别?mysql中的表锁有哪些类型?行锁是如何工作的?什么情况下会触发行锁?如何在MySQL中手动获取行锁?行锁和表锁在性能上有什么区别?如何优化数据库并发性能?举例说
    Mysql行锁和表锁的实现示例
    2024-08-19

    【MySQL】说透锁机制(二)行锁 加锁规则 之 范围查询(你知道会锁表吗?)

    本文会按照 聚集集索->唯一索引->普通索引 的顺序 地毯式分析 范围查询中 、、>、>= 的行锁情况,锁表分析在唯一索引 章节,万字长文,力求分析全面,很硬核全网独一份,记得收藏! 当然如果落下什么欢迎大家评论指出! 前文回顾 在上
    2023-08-16

    Redis中的分布式锁如何实现可重入性和防止死锁的机制?

    Redis提供了分布式锁的实现方案,但是在实际应用中,需要考虑到分布式锁的可重入性和防止死锁的机制。
    Redis数据库2024-11-30

    MySQL悲观锁与乐观锁如何实现

    这篇文章主要为大家展示了“MySQL悲观锁与乐观锁如何实现”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“MySQL悲观锁与乐观锁如何实现”这篇文章吧。前言悲观锁和乐观锁是用来解决并发问题的两种思
    2023-06-25

    mysql悲观锁和乐观锁如何实现

    悲观锁是在对数据进行操作之前就先加锁,防止其他事务对数据进行修改,从而确保数据的一致性。在MySQL中,可以通过使用SELECT … FOR UPDATE语句来实现悲观锁。例如:START TRANSACTION;SELECT * FR
    mysql悲观锁和乐观锁如何实现
    2024-05-08

    如何在 MySQL 中查询数据库死锁?(mysql如何查询数据库死锁)

    在 MySQL 数据库中,查询数据库死锁是一项重要的任务,它可以帮助数据库管理员及时发现和解决死锁问题,确保数据库的正常运行。以下是在 MySQL 中查询数据库死锁的详细步骤:

    一、了解数据库死锁的概念

    数据库死锁是指两个或多个事务在并发执行过程中,互相等待对方持有的锁,导致这些事务都无法继续执行的情况。死锁会导致数据库性能下降,甚至可能导致数据库系统崩溃。因此,及时查询和解决数据库死锁是非常重要的。

    二、使用 MySQL 的系统表查询死锁信息

    MySQL 提供了一些系统表,可以用于查询数据库死锁信息。以下是常用的系统表:

    1. INNODB_TRX:该表存储了当前正在运行的事务信息,包括事务 ID、事务状态、开始时间等。
    2. INNODB_LOCKS:该表存储了当前系统中的锁信息,包括锁 ID、事务 ID、锁类型等。
    3. INNODB_LOCK_WAITS:该表存储了事务之间的锁等待关系,包括等待事务 ID、被等待事务 ID 等。

    通过查询这些系统表,可以获取到关于数据库死锁的详细信息。以下是一个查询数据库死锁的示例 SQL 语句:

    SELECT
        trx.trx_mysql_thread_id AS \'Thread ID\',
        trx.trx_query AS \'Query\',
        lw.wait_started AS \'Wait Started\',
        lw.requested_lock_id AS \'Requested Lock\',
        lw.blocking_lock_id AS \'Blocking Lock\'
    FROM
        information_schema.INNODB_TRX trx
            JOIN
        information_schema.INNODB_LOCK_WAITS lw ON trx.trx_id = lw.waiting_trx_id
            JOIN
        information_schema.INNODB_LOCKS l ON lw.requested_lock_id = l.lock_id
    ORDER BY
        lw.wait_started DESC;

    上述 SQL 语句通过连接 INNODB_TRXINNODB_LOCK_WAITSINNODB_LOCKS 这三个系统表,获取到了当前正在等待锁的事务信息、等待的锁信息以及被等待的锁信息,并按照等待开始时间降序排列。

    三、分析查询结果

    执行上述 SQL 语句后,会返回一个包含死锁信息的结果集。需要对结果集进行分析,以确定死锁的原因和涉及的事务。以下是一些常见的死锁情况和分析方法:

    1. 事务长时间等待锁:如果查询结果中某个事务的等待时间较长,可能是因为该事务在等待其他事务持有的锁。可以通过查看该事务的查询语句和等待的锁信息,确定是否存在死锁的可能性。
    2. 多个事务相互等待:如果查询结果中显示多个事务相互等待对方持有的锁,那么很可能存在死锁。需要进一步分析这些事务的查询语句和锁信息,确定死锁的原因和解决方法。
    3. 锁冲突:如果查询结果中显示某个锁被多个事务同时请求,那么可能存在锁冲突。需要检查事务的查询逻辑,看是否可以调整事务的执行顺序,以避免锁冲突。

    四、解决数据库死锁

    一旦确定了数据库死锁的原因,就可以采取相应的措施来解决死锁。以下是一些常见的解决方法:

    1. 调整事务的执行顺序:如果死锁是由于事务的执行顺序不当导致的,可以尝试调整事务的执行顺序,以避免锁冲突。
    2. 优化事务的逻辑:如果死锁是由于事务的逻辑不合理导致的,可以优化事务的逻辑,减少事务持有锁的时间和范围。
    3. 增加锁的超时时间:如果死锁是由于事务等待锁的时间过长导致的,可以增加锁的超时时间,避免事务长时间等待锁。
    4. 使用合适的锁机制:根据业务需求,选择合适的锁机制,以避免死锁的发生。例如,可以使用行级锁代替表级锁,或者使用乐观锁代替悲观锁。

    五、预防数据库死锁

    除了及时查询和解决数据库死锁之外,还可以采取一些措施来预防数据库死锁的发生。以下是一些常见的预防方法:

    1. 设计合理的数据库结构:设计合理的数据库结构,避免不必要的锁冲突。例如,可以使用分区表、索引等技术,提高数据库的并发性能。
    2. 规范事务的使用:规范事务的使用,避免事务的嵌套和长时间持有锁。可以使用事务的开始、提交和回滚语句,明确事务的边界。
    3. 监控数据库性能:定期监控数据库的性能,及时发现和解决潜在的问题。可以使用 MySQL 的监控工具,如 PERFORMANCE_SCHEMA,获取数据库的性能指标和锁信息。

    总之,查询数据库死锁是 MySQL 数据库管理中一项重要的任务。通过使用 MySQL 的系统表查询死锁信息,并分析和解决死锁问题,可以确保数据库的正常运行。同时,还可以采取一些预防措施,避免死锁的发生。

    如何在 MySQL 中查询数据库死锁?(mysql如何查询数据库死锁)
    2024-12-13

    编程热搜

    目录