Tortoise事务需显式await in_transaction()并统一using_db=conn,select_for_update()仅PostgreSQL真实加锁,SQLite静默忽略;事务内禁用耗时操作,多模型操作须共用同一conn。

事务必须显式 await,不能只写 await transaction
很多人以为只要在 async 函数里用 transaction 上下文就自动生效,其实不是。Tortoise 的事务必须显式调用 start() 和 commit()/rollback(),或者用 async with 包裹——但这个 async with 是 in_transaction() 返回的异步上下文管理器,不是直接对 transaction 变量使用。
常见错误是这样写:
transaction = Tortoise.get_connection("default").in_transaction()
await transaction # ❌ 错误:这不会开启事务,只是 await 一个未启动的上下文
正确做法是:
- 用
async with Tortoise.get_connection("default").in_transaction() as conn: - 所有模型操作(
.create()、.save()、.filter().update()等)必须传入using_db=conn - 不传
using_db的操作会走默认连接,脱离事务控制
select_for_update() 在 PostgreSQL 中才真正阻塞,SQLite 不支持
高并发下防超卖、抢号等场景依赖行级锁,但 select_for_update() 行为因数据库而异:
立即学习“Python免费学习笔记(深入)”;
- PostgreSQL:
select_for_update()会真实加SELECT ... FOR UPDATE锁,其他事务读同一行会被阻塞 - MySQL(via aiomysql):部分支持,但需确认隔离级别为
REPEATABLE READ或更高 - SQLite(via aiosqlite):
select_for_update()被静默忽略,**无任何锁效果**,高并发下可能出错
示例(安全写法):
async with in_transaction() as conn:
item = await Item.get(id=123).select_for_update(using_db=conn)
if item.stock > 0:
item.stock -= 1
await item.save(using_db=conn)
注意:select_for_update() 必须和后续修改在同一个事务中,且都指定 using_db=conn。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
避免在事务中做非数据库耗时操作
事务持有锁的时间越长,竞争越激烈。以下操作会显著拖长事务窗口:
- 调用外部 HTTP API(如支付回调验证)
- 执行复杂计算或文件 I/O
- 等待 asyncio.sleep() 或未优化的
await链
正确策略是:
- 只在事务内做「查 + 改 + 保存」三件事
- 把校验逻辑前置(比如库存是否足够,用
.filter(stock__gt=0)先查) - 把副作用(发消息、记日志、调第三方)移到事务外,用最终一致性补偿
多模型跨表更新必须共用同一 using_db 实例
高并发事务常涉及多个模型联动,比如扣库存 + 写订单 + 更新用户积分。如果每个模型操作没统一指定事务连接,就会变成多个独立事务,失去原子性。
错误示范:
async with in_transaction() as conn:
await Order.create(...) # ✅ 使用 conn
await User.filter(id=1).update(points=F("points") + 10) # ❌ 没传 using_db,走默认连接
正确写法:
- 所有
.create()、.update()、.delete()显式传using_db=conn - 对 QuerySet 使用
.using_db(conn)方法切换上下文 - 关联模型操作(如
item.orders.all())也要手动指定using_db=conn,它不会自动继承
最易被忽略的是:模型关系的反向查询(如 user.orders)默认不走当前事务连接,必须重写为 await Order.filter(user_id=user.id).using_db(conn)。

















