← 中文资源

简体中文版本

带回滚的事务上下文管理器

用 contextmanager 实现事务边界:正常退出时提交计数,发生任何异常时恢复快照、记录回滚并把异常继续抛出。

阅读英文原文

功能说明

Store.transaction() 是一个基于 @contextmanager 的事务边界。进入时复制一份字典快照,正常退出时只增加提交计数;只要代码块里抛出任何异常,就把字典恢复成快照、增加回滚计数,并把原异常继续抛出。示例先做一次成功写入,再模拟支付失败,展示数据在异常后回到事务开始前的状态。

关键代码

snapshot = dict(self.data)
tx = Transaction(self)
try:
    yield tx
except BaseException:
    self.data = snapshot
    self.rollbacks += 1
    raise
else:
    self.commits += 1

捕获 BaseException 是为了让 KeyboardInterrupt 和 SystemExit 也触发回滚;如果只捕获 Exception,中断时数据会停留在半更新状态。

使用注意

  • 快照是浅拷贝,嵌套的可变对象仍被共享;需要深拷贝时改用 copy.deepcopy。
  • 事务对象只是操作入口,没有隔离级别,也不支持并发写;多线程场景需要额外加锁。
  • 回滚会替换整个字典,外部持有的旧字典引用不会自动更新。
  • 提交阶段没有持久化动作,真实项目应在 else 分支里写文件或提交数据库。
  • 不要在事务里吞掉异常再继续,否则上下文管理器会认为操作成功并提交。

验证方式

运行输出应依次显示提交后的余额与币种、回滚提示,以及回滚后的原始数据;commits 为 1、rollbacks 为 1。可以再加一个 raise 场景,确认异常类型和消息原样抛出。