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
相关产品推荐
相关产品推荐

