温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Cursor游标怎么避免死锁

发布时间:2026-10-30 20:13:58 来源:亿速云 阅读:86 作者:小樊 栏目:数据库

在数据库(如 MySQL、PostgreSQL、Oracle 等)中使用 游标(Cursor) 进行批量处理时,确实容易引发 死锁(Deadlock),尤其在高并发环境下。下面从 原因 → 设计原则 → 具体避免手段 系统说明。


一、游标为什么会引发死锁?

常见原因包括:

  1. 加锁顺序不一致
    • 不同事务以不同顺序更新同一批数据
  2. 游标逐行更新 + 长事务
    • 游标打开时间长,锁持有久
  3. SELECT … FOR UPDATE 使用不当
    • 锁范围过大或无序
  4. 多表关联更新
    • 表之间加锁顺序不同
  5. 在游标循环里访问其他表
    • 形成交叉锁

二、避免游标死锁的核心原则

✅ 原则 1:统一加锁顺序(最重要)

所有事务必须按相同顺序访问和更新资源

❌ 错误示例:

  • 事务 A:先更新 user,再更新 order
  • 事务 B:先更新 order,再更新 user

✅ 正确:

  • 永远先 user → 再 order

✅ 原则 2:游标内只做“最小必要操作”

游标中:

  • 不要做复杂逻辑
  • 不要调用外部接口
  • 不要嵌套事务

✅ 推荐模式:

OPEN cur;
LOOP
  FETCH cur INTO rec;
  EXIT WHEN cur%NOTFOUND;
  UPDATE ... WHERE id = rec.id;
END LOOP;
CLOSE cur;

✅ 原则 3:使用有序游标(ORDER BY 主键)

无序游标容易导致:

  • 不同事务锁不同页
  • 死锁概率上升

✅ 推荐:

DECLARE cur CURSOR FOR
SELECT id FROM orders
ORDER BY id;

✅ 原则 4:控制事务大小(批量提交)

❌ 错误:

OPEN cur;
LOOP
  UPDATE ...
END LOOP;
COMMIT; -- 事务太长

✅ 正确(每 N 条提交):

DECLARE
  cnt NUMBER := 0;
BEGIN
  FOR rec IN cur LOOP
    UPDATE ...;
    cnt := cnt + 1;
    IF cnt >= 1000 THEN
      COMMIT;
      cnt := 0;
    END IF;
  END LOOP;
  COMMIT;
END;

✅ 原则 5:避免 SELECT … FOR UPDATE 范围过大

❌ 危险:

SELECT * FROM orders FOR UPDATE;

✅ 安全:

SELECT id FROM orders
WHERE status = 'NEW'
ORDER BY id
FOR UPDATE;

✅ 原则 6:设置锁等待超时(兜底)

MySQL

SET innodb_lock_wait_timeout = 5;

Oracle

ALTER SESSION SET ddl_lock_timeout = 10;

PostgreSQL

SET lock_timeout = '5s';

✅ 原则 7:死锁后自动重试(工程级方案)

死锁无法 100% 避免时,应:

  • 捕获死锁异常
  • 短暂 sleep
  • 重新执行游标逻辑

示例(伪代码):

retry = 3
while retry > 0:
  try:
    process_cursor()
    break
  catch Deadlock:
    sleep(random)
    retry -= 1

三、游标死锁典型反模式 ❌

反模式 风险
游标内再开游标 交叉锁
先 SELECT 再 UPDATE 非原子
无 ORDER BY 随机死锁
单事务处理百万行 长事务
更新非主键条件 锁范围大

四、更优替代方案(如果可以)

如果业务允许,尽量不用游标:

  • ✅ 批量 UPDATE
  • ✅ INSERT … SELECT
  • ✅ 分页 UPDATE(LIMIT + ORDER BY)
  • ✅ 后台任务 + 队列

五、总结一句话

游标避免死锁 = 统一锁顺序 + 有序访问 + 小事务 + 短锁时间 + 可重试

如果你能告诉我:

  • 使用的数据库(MySQL / Oracle / PG)
  • 是否使用 FOR UPDATE
  • 是否多表更新

我可以给你针对性的游标写法示例。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手