You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 1.4.22自动提交默认开启时如何临时关闭以实现回滚?

解决Django 1.4.22中dry_run模式下回滚失效的问题

首先,我得拆解下你遇到的核心问题:Django 1.4.22默认autocommit=True且无法全局修改,你用了@transaction.commit_manually装饰器,但dry_run里的回滚操作没生效,导致测试用例失败。

问题根源分析

从你的代码来看,最大的可能是你使用的self.cursor没有纳入Django的事务管理体系。Django的transaction模块只能管控它自己创建的数据库连接(即django.db.connection),如果你的self.cursor是通过自定义数据库连接生成的,那transaction.rollback()根本影响不到这些操作,自然回滚失效。

另外,在Django 1.4中,@transaction.commit_manually装饰器确实会临时关闭autocommit,但前提是所有数据库操作都通过Django提供的cursor执行。

解决方案:改用Django官方的数据库连接

下面是修改后的代码,核心是替换自定义cursor为Django的connection.cursor(),并调整事务逻辑:

from django.db import connection, transaction
import logging

logger = logging.getLogger(__name__)

@transaction.commit_manually
def run(self, dry_run):
    try:
        assert self.database in self.validate_values.keys()
        assert self.table in self.validate_values.values()
    except AssertionError as e:
        logger.error("%s or %s is not available. \n Error: %s" % (self.database, self.table, e.message))
        return

    # 使用Django官方的cursor,确保纳入事务管理
    cursor = connection.cursor()
    cursor.execute(self.SELECT_PATTERN % self.PGDict)
    current_value = cursor.fetchall()

    if len(current_value) > 1:
        logger.error("You can only update one item at a time.\n Current value: %s" % current_value)
        return
    elif len(current_value) == 0:
        logger.error("No data.")
        return
    elif len(current_value) == 1:
        if dry_run:
            logger.warning("Data below will be deleted.\n")
            logger.info("Current value: %s" % current_value)
            try:
                # 执行删除操作(此时在事务中,不会自动提交)
                cursor.execute(self.DELETE_PATTERN % self.PGDict)
                # 验证删除结果
                cursor.execute(self.SELECT_PATTERN % self.PGDict)
                deleted_check = cursor.fetchall()
                assert len(deleted_check) == 0

                # 手动回滚事务,恢复数据
                transaction.rollback()
                logger.info("Dry run successfully.")

                # 再次查询确认数据已恢复
                cursor.execute(self.SELECT_PATTERN % self.PGDict)
                actual_value = cursor.fetchall()
                print(actual_value)
                return actual_value
            except AssertionError as e:
                # 出错时也要确保回滚事务
                transaction.rollback()
                logger.error("Dry run failed. \n Error: %s" % e.message)
                return
        else:
            logger.warning("Data deleting...\n")
            cursor.execute(self.DELETE_PATTERN % self.PGDict)
            cursor.execute(self.SELECT_PATTERN % self.PGDict)
            current_value = cursor.fetchall()
            try:
                assert len(current_value) == 0
                # 手动提交事务,确认删除
                transaction.commit()
                logger.info("Done.")
                return len(current_value)
            except AssertionError as e:
                # 删除失败,回滚
                transaction.rollback()
                logger.error("Deletion failed. \n Error: %s" % e.message)
                return
    else:
        logger.error("Value Error")
        return

关键修改点说明

  1. 替换cursor来源:用connection.cursor()替代self.cursor,确保所有数据库操作都在Django的事务管控范围内。
  2. 明确事务操作:在非dry_run模式下,删除成功后必须手动调用transaction.commit();无论成功失败,dry_run模式下都要调用transaction.rollback()。
  3. 移除savepoint:在Django 1.4的commit_manually模式下,直接使用全局事务的rollback更可靠,savepoint反而可能增加复杂度。

测试用例验证

你的测试用例test_run_dry_run现在应该能正常通过了:执行dry_run后,数据会被回滚,查询结果依然是原始的123456,长度为1,符合断言条件。

内容的提问来源于stack exchange,提问作者FakeYG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:24:11