• 数据库-mysql-死锁的发生示例


    例1:-------------------------------------------------------------------------------------------------------------------------------------

    T1:select * from table lock in share mode(假设查询会花很长时间,下面的例子也都这么假设)

    T2:update table set column1='hello'

    过程:

    T1运行(并加共享锁)

    T2运行

    If T1还没执行完

    T2等......

    else 锁被释放

    T2执行

    end if

    T2 之所以要等,是因为 T2 在执行 update 前,试图对 table 表加一个排他锁,而数据库规定同一资源上不能同时共存共享锁和排他锁。所以 T2 必须等 T1 执行完,释放了共享锁,才能加上排他锁,然后才能开始执行 update 语句。

    例2:-------------------------------------------------------------------------------------------------------------------------------------

    T1:select * from table lock in share mode

    T2:select * from table lock in share mode

    这里T2不用等待T1执行完,而是可以马上执行。

    分析:

    T1运行,则 table 被加锁,比如叫lockA,T2运行,再对 table 加一个共享锁,比如叫lockB,两个锁是可以同时存在于同一资源上的(比如同一个表上)。这被称为共享锁与共享锁兼容。这意味着共享锁不阻止其它人同时读资源,但阻止其它人修改资源。

    例3:-------------------------------------------------------------------------------------------------------------------------------------

    T1:select * from table lock in share mode

    T2:select * from table lock in share mode

    T3:update table set column1='hello'

    T2 不用等 T1 运行完就能运行,T3 却要等 T1 和 T2 都运行完才能运行。因为 T3 必须等 T1 和 T2 的共享锁全部释放才能进行加排他锁然后执行 update 操作。

    例4:(死锁的发生)-----------------------------------------------------------------------------------------------------------------

    T1:begin tran

         select * from table lock in share mode

         update table set column1='hello'

    T2:begin tran

         select * from table lock in share mode

         update table set column1='world'

    假设 T1 和 T2 同时达到 select,T1 对 table 加共享锁,T2 也对 table 加共享锁,当 T1 的 select 执行完,准备执行 update 时,根据锁机制,T1 的共享锁需要升级到排他锁才能执行接下来的 update。在升级排他锁前,必须等 table 上的其它共享锁(T2)释放,同理,T2 也在等 T1 的共享锁释放。于是死锁产生了。

    例5:-------------------------------------------------------------------------------------------------------------------------------------

    T1:begin tran

         update table set column1='hello' where id=10

    T2:begin tran

         update table set column1='world' where id=20

    这种语句虽然最为常见,很多人觉得它有机会产生死锁,但实际上要看情况

    |--如果id是主键(默认有主键索引),那么T1会一下子找到该条记录(id=10的记录),然后对该条记录加排他锁,T2,同样,一下子通过索引定位到记录,然后对id=20的记录加排他锁,这样T1和T2各更新各的,互不影响。T2也不需要等。

    |--如果id是普通的一列,没有索引。那么当T1对id=10这一行加排他锁后,T2为了找到id=20,需要对全表扫描。但因为T1已经为一条记录加了排他锁,导致T2的全表扫描进行不下去(其实是因为T1加了排他锁,数据库默认会为该表加意向锁,T2要扫描全表,就得等该意向锁释放,也就是T1执行完成),就导致T2等待。

    死锁怎么解决呢?一种办法是,如下:

    例6:-------------------------------------------------------------------------------------------------------------------------------------

    T1:begin tran

         select * from table for update

         update table set column1='hello'

    T2:begin tran

         select * from table for update

         update table set column1='world'

    这样,当 T1 的 select 执行时,直接对表加上了排他锁,T2 在执行 select 时,就需要等 T1 事物完全执行完才能执行。排除了死锁发生。但当第三个 user 过来想执行一个查询语句时,也因为排他锁的存在而不得不等待,第四个、第五个 user 也会因此而等待。在大并发情况下,让大家等待显得性能就太友好了。

    所以,有些数据库这里引入了更新锁(如Mssql,注意:Mysql不存在更新锁)。

    例7:-------------------------------------------------------------------------------------------------------------------------------------

    T1:begin tran

         select * from table [加更新锁操作]

         update table set column1='hello'

    T2:begin tran

         select * from table [加更新锁操作]

         update table set column1='world'

    更新锁其实就可以看成排他锁的一种变形,只是它也允许其他人读(并且还允许加共享锁)。但不允许其他操作,除非我释放了更新锁。T1 执行 select,加更新锁。T2 运行,准备加更新锁,但发现已经有一个更新锁在那儿了,只好等。当后来有 user3、user4...需要查询 table 表中的数据时,并不会因为 T1 的 select 在执行就被阻塞,照样能查询,相比起例6,这提高了效率。

    附:意向锁和计划锁:

    计划锁,和程序员关系不大,就没去了解。
    意向锁(innodb特有)分意向共享锁和意向排他锁。
    意向共享锁:表示事务获取行共享锁时,必须先得获取该表的意向共享锁;
    意向排他锁:表示事务获取行排他锁时,必须先得获取该表的意向排他锁;
    我们知道,如果要对整个表加锁,需保证该表内目前不存在任何锁。

    因此,如果需要对整个表加锁,那么就可以根据:检查意向锁是否被占用,来知道表内目前是否存在共享锁或排他锁了。而不需要再一行行地去检查每一行是否被加锁。

  • 相关阅读:
    python3--字符串
    python3--数字运算,取数
    全栈项目|小书架|服务器开发-用户模块设计(用户表设计,注册登录,退出登录)
    全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证
    全栈项目|小书架|服务器开发-JWT 详解
    全栈项目|小书架|服务器开发-Koa2中间件机制洋葱模型了解一下
    全栈项目|小书架|服务器开发-NodeJS 中使用 Sequelize 操作 MySQL数据库
    全栈项目|小书架|服务器开发-Koa2 连接MySQL数据库(Navicat+XAMPP)
    全栈项目|小书架|服务器开发-Koa2 参数校验处理
    全栈项目|小书架|服务器开发-Koa2 全局异常处理
  • 原文地址:https://www.cnblogs.com/sunshinekevin/p/14237732.html
Copyright © 2020-2023  润新知