首页
/ Drift数据库事务中外部创建语句导致死锁问题分析

Drift数据库事务中外部创建语句导致死锁问题分析

2025-06-28 06:49:16作者:卓艾滢Kingsley

问题现象

在使用Drift数据库库时,开发者遇到一个特殊的事务执行问题:当在事务外部创建SQL语句对象,然后在事务内部执行时,事务会卡死无法完成。具体表现为事务只执行了部分SQL语句后就停滞不前。

问题复现代码

Future<void> changeNoteParent({
  required String noteId,
  required String parentNoteId,
  required String newParentNoteId,
  required int newPositon
}) async {
  final branch = await getBranch(noteId, parentNoteId);
  // 问题点:在事务外部创建更新语句
  final sql = db.update(db.branches)
    ..where((branches) => 
        branches.noteId.equals(noteId) &
        branches.parentNoteId.equals(parentNoteId));
  
  final data = BranchesCompanion(
    parentNoteId: Value(newParentNoteId),
    position: Value(newPositon),
    utcModified: Value(TimeTool.utcms),
  );
  
  await db.transaction(() async {
    await db.customStatement(
      'UPDATE branches SET position = position + 1 WHERE parentNoteId = ? AND position >= ?',
      [newParentNoteId, newPositon],
    );
    // 在事务内部执行外部创建的语句
    await sql.write(data);
    await db.customStatement(
      'UPDATE branches SET position = position - 1 WHERE parentNoteId = ? AND position >= ?',
      [parentNoteId, branch.position],
    );
  });
}

问题本质

这个问题源于Drift库的事务处理机制存在一个缺陷:当SQL语句对象在事务外部创建,但在事务内部执行时,Drift未能正确地将该语句纳入当前事务上下文中。这会导致数据库连接状态不一致,最终引发死锁。

解决方案

临时解决方案

开发者可以简单地将语句创建移到事务内部:

await db.transaction(() async {
  final sql = db.update(db.branches)
    ..where((branches) => 
        branches.noteId.equals(noteId) &
        branches.parentNoteId.equals(parentNoteId));
  
  // 其他操作
  await sql.write(data);
});

根本修复

Drift库的维护者已在最新版本中修复了这个问题(提交7f7d2ab1b0a03383eb6acd30ca376026720ce347)。修复后,无论语句是在事务内部还是外部创建,只要在事务中执行,都会被正确纳入事务上下文。

最佳实践建议

  1. 语句创建位置:为了代码清晰和避免潜在问题,建议总是在事务内部创建需要在该事务中执行的语句对象。

  2. 事务边界明确:确保事务中的所有数据库操作都在事务回调函数内部完成,不要将事务操作分散到多个函数中。

  3. 错误处理:事务中应包含适当的错误处理,确保在发生异常时能够回滚事务。

  4. 版本升级:建议升级到已修复此问题的Drift版本,以获得更稳定的行为。

总结

这个问题展示了数据库事务处理中的一个重要原则:事务内的所有操作应该在同一个上下文中创建和执行。Drift库的修复确保了API行为更加符合开发者的直觉,同时也提醒我们在使用ORM库时要注意事务边界和语句生命周期管理。

登录后查看全文
热门项目推荐

热门内容推荐

最新内容推荐

项目优选

收起
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
176
262
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
863
511
ShopXO开源商城ShopXO开源商城
🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信+支付宝+百度+头条&抖音+QQ+快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循MIT开源协议发布、基于ThinkPHP8框架研发
JavaScript
93
15
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
129
182
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
259
300
kernelkernel
deepin linux kernel
C
22
5
cherry-studiocherry-studio
🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端
TypeScript
596
57
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.07 K
0
HarmonyOS-ExamplesHarmonyOS-Examples
本仓将收集和展示仓颉鸿蒙应用示例代码,欢迎大家投稿,在仓颉鸿蒙社区展现你的妙趣设计!
Cangjie
398
371
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
332
1.08 K