You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server插入锁问题:同ID操作引发死锁原因咨询

同一ID下ORM操作引发死锁的原因分析

我用下面的代码向数据库插入数据时完全正常:

Employe emp1=new Employe ();
emp1.setId(12);
getCurrentSession().saveOrUpdate(emp1);
getCurrentSession().flush();
Employe emp2=new Employe ();
emp2.setId(12);
entityManager.merge(emp2);
entityManager.flush();

但换成下面的代码就会出现死锁:

Employe emp1=new Employe ();
emp1.setId(12);
getCurrentSession().saveOrUpdate(emp1);
Employe emp2=new Employe ();
emp2.setId(12);
entityManager.merge(emp2);
entityManager.flush();
getCurrentSession().flush();

为什么会触发死锁,而不是先插入第一条再刷新、接着处理第二条?注:两个操作使用的是同一个ID。


核心原因拆解

  • 正常代码的执行逻辑:
    第一个代码里,getCurrentSession().flush()会立刻把saveOrUpdate(emp1)的操作同步到数据库,此时数据库对ID=12的行加锁,flush完成后锁直接释放。后续执行merge(emp2)再flush时,操作同一行但无锁冲突,自然顺利完成。

  • 死锁代码的问题所在:
    第二个代码中,saveOrUpdate(emp1)之后没有立刻flush,这个操作被存在Hibernate会话缓存里,数据库还没实际执行。接下来调用entityManager.merge(emp2)并执行entityManager.flush(),此时ORM会优先处理merge的操作,尝试获取ID=12行的锁并执行。而此时saveOrUpdate(emp1)的操作还在缓存中,后续调用getCurrentSession().flush()时,需要执行这个缓存的操作,同样需要ID=12行的锁。

    关键是getCurrentSession()和entityManager本质是同一会话的不同封装,共用同一个数据库连接和事务上下文。同一事务内,merge操作已经持有行锁,saveOrUpdate操作又要申请同一行的锁,就造成了锁等待的死锁场景——两个操作在同一个事务里互相等对方释放锁,最终触发死锁。

内容的提问来源于stack exchange,提问作者Ali Khalil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:51:12