#根据日志可以看出两个进程(Process 2027023 和 1942222)形成了循环等待共享锁(ShareLock) 的局面,导致彼此无法继续执行。
Detail:
Process 2027023 waits for ShareLock on transaction 239263072; blocked by process 1942222.
Process 1942222 waits for ShareLock on transaction 239269188; blocked by process 2027023.死锁的发生需满足四个条件:互斥、持有并等待、不可剥夺、循环等待。此处的关键是循环等待:
进程 2027023 持有事务 239269188 的 ShareLock,同时等待进程 1942222 持有的事务 239263072 的 ShareLock;
进程 1942222 持有事务 239263072 的 ShareLock,同时等待进程 2027023 持有的事务 239269188 的 ShareLock;
两者相互等待对方释放资源,形成闭环,导致死锁。
数据库通常会自动检测死锁并终止其中一个进程(“牺牲品”)以释放资源。若需手动干预,需优先终止回滚代价更低的进程:
如何选择终止的进程?
看事务执行阶段:若某进程刚启动(执行时间短、修改数据少),回滚代价低,优先终止;
看业务重要性:非核心业务进程优先终止,减少对关键流程的影响;
看锁持有数量:持有锁越少的进程,回滚时释放资源的成本越低。
假设通过日志确认进程 1942222 执行时间更短、修改数据更少,可手动终止:
-- 以SQL Server为例,终止进程(PID为1942222)
KILL 1942222;
通过查看日志发现,执行的sql为:update t_cas_checkedresult set fbatchno = 0,fcreatorid=1585444342057698305
没有WHERE子句 → 会全表更新(锁表中所有记录)
全表更新的执行流程:
事务 A 获取全表的写锁(ROW EXCLUSIVE LOCK)
按物理顺序逐行更新记录
若此时有其他事务 B 也在更新同一表(即使是不同行),会因锁冲突导致死锁无WHERE条件的全表更新是高风险操作,在生产环境中必须避免。通过明确过滤条件、添加索引和分批处理,可以有效避免死锁,并显著提升更新性能。