Mysql数据库锁的一个问题

  • T
    Texan
    默认隔离级别 可重复读, autocommit=1, 建表:
    CREATE TABLE `test` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `age` tinyint(3) DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `idx_age` (`age`) USING BTREE
    ) ENGINE=InnoDB ;


    INSERT into test (id,age) values (1,1);



    session 1:
    update test set age=1 where id=1;


    session 2:
    update test set id=1 where age =1;





    那么 session 1 和 2是否有可能产生死锁?


    session 1是先锁主键,再锁二级索引. session 2是先锁二级索引再锁主键.

    我在本地上各开了二十个线程来不停update,没有出现死锁. 为什么呢?
  • 2
    269569205
    因为你cpu够快 20个线程瞬间执行完毕
  • P
    Pyrrhus
    普通的update是一次就commit掉的,你要把它们放在事务里
  • T
    Texan
    抱歉,我的意思是, 20个线程执行第一条,每个线程update 1万次. 20个线程执行第二个update, 也是每个线程1万次.
    没有发现死锁.
  • T
    Texan
    autocommit=1, 这个update本来就是事务里啊.
    我只是不知道一条update语句锁了两个索引的过程,是不是一个原子性的动作.
  • s
    shuihen
    手动commit
  • P
    Pyrrhus
    你还是没搞清死锁的原理,
    死锁是在锁表前发现有其他事务已经将表锁住,在等待另外事务的解锁,

    而你只有2个事务,前面那个事务解锁,后一个就能顺利运行,
    一般要测死锁要开3个进程,这样才能骗过系统。
  • t
    txkingzjg
    mark下,系统偶然出现死锁,很难重现,死锁原理也懂,但是就是没法根治问题,烦人
  • I
    IAmThrilling
    那个回帖解释很清楚了,死锁出现原因就是进程等待,你这种情况操作很快完成,没机会等待多久 iOS fly ~
  • T
    Texan
    我比较好奇的就是, 这种死锁情况理论上是否会出现?

    比如说UUID是有概率重复的,而且我们可以估算出来概率。
  • I
    IAmThrilling
    貌似你那两个语句理论上也不会锁
  • T
    Texan
    https://ruby-china.org/topics/38429发现了这篇文章, 两条简单的update语句导致死锁
    文章的大意就是,

    'a', 'b' 是表里两个索引

    session 1:
    update t set c=1where (a=1 and b =1)

    session 2:
    update t set c=1 where (a=2 and b =2)


    这样也可能产生死锁
  • T
    Texan
    看12L
  • l
    lumi
    顺序执行,有等待但不死锁
  • H
    Hisoka-J
    一会我给你跑一个 iOS fly ~
  • I
    IAmThrilling
    你第一个session where 不会触发行锁 iOS fly ~
  • x
    xx6412223
    不会死锁,最多是第二个线程等待超时。
    死锁的概念是两个线程对两个资源同时上锁,但是每个都只拿到其中一个资源,等待第二个资源释放。
    操作系统原理对死锁一个比喻是,两个人吃面条只用一副刀叉

    手动模拟的话,开两个sesaion 并且手动提交事务,第一个where a=1 for update 第二个where a =2 for update .切回第一个session再次 where a=2 for update ,就有死锁了
  • s
    swordf
    死锁必要条件:互斥使用资源,占有并等待资源,资源不可抢夺,循环等待资源。第二条不成立吧?
  • T
    Texan
    我跑过了,十个线程,每个有一个储存过程, 不停循环update, 也就是第一条语句. 另外十个线程,另外一个储存过程,第二条语句. CPU已经100%占用了. 跑了五分钟.
    可以看到对聚簇索引和二级索引分别的锁的请求,但是死锁信息. 应该是源码里面用了其他机制来保证每个语句里面获取的两把锁,都是原子性一起获取的.