Python Django+;MySQL:保存点不存在?

Python Django+;MySQL:保存点不存在?,python,mysql,django,Python,Mysql,Django,我正在一个共享托管计划上运行一个小型Web应用程序。 我有一个“worker函数”,它包含一个无限循环;循环检查数据库中的任务队列,以查找要执行的新任务。这就需要手动使用@transaction.commit\u,以击败Django的缓存并获取每次迭代的最新信息 我最近实现了DB日志记录,因此需要在我的worker函数中引入使用保存点-这样,如果出现任何错误,我可以回滚到一个好的保存点,登录到数据库,并继续执行,直到到达最后的事务。commit() 现在,与我的开发服务器不同,生产服务器给了我一

我正在一个共享托管计划上运行一个小型Web应用程序。 我有一个“worker函数”,它包含一个无限循环;循环检查数据库中的任务队列,以查找要执行的新任务。这就需要手动使用
@transaction.commit\u
,以击败Django的缓存并获取每次迭代的最新信息

我最近实现了DB日志记录,因此需要在我的worker函数中引入使用保存点-这样,如果出现任何错误,我可以回滚到一个好的保存点,登录到数据库,并继续执行,直到到达最后的
事务。commit()

现在,与我的开发服务器不同,生产服务器给了我一个错误:

 DatabaseError: (1305, 'SAVEPOINT s140364713719520_x1 does not exist')
指向
事务。在
块中调用savepoint\u rollback()。dev服务器没有这样的问题;如果我在交互式shell中键入
transaction.savepoint()
,生产服务器会很高兴地生成保存点ID

,如果有帮助的话;我尽量保持简洁


如果有任何仁慈的巨蟒大师,请帮助我。我对此感到非常沮丧,尽管我认为我在平静地处理这件事方面做得相当好。

如果你查看Django上与之相关的文档,会发现并非所有人都支持它们。基本上,MyISAM不处理事务,所以您不需要回滚,InnoDB需要回滚。因此,我将检查dev和prod表是否都使用相同的存储引擎类型。您可以通过运行以下命令进行检查:

SHOW CREATE TABLE mytable

我偶尔也会犯同样的严重错误:

OperationalError: (1305, 'SAVEPOINT {{name}} does not exist')
谷歌并没有说得更清楚,只是说这是一种“正常”的并发问题。所以它是不确定的,并且很难在开发环境中重现

幸运的是,通过使生产应用程序日志记录足够详细,我能够对其进行本地化

原因 在MySQL中,有一些操作可以隐式结束事务:

  • DDL语句(例如,
    CREATE TABLE
    ALTER TABLE
    等)导致隐式提交。众所周知,MySQL中的DDL不是事务性的
  • OperationalError:(1213,“尝试获取锁时发现死锁;尝试重新启动事务”)
    OperationalError:(1205,“超过锁等待超时;尝试重新启动事务”)
    导致隐式回滚
因此,第二个案例的结果确实有些“正常”。它可以由以下代码表示:

更新
请注意,上面提到的异常阴影是针对Python2的。Python 3实现了,如果出现死锁,回溯将包含所有相关信息。

我在两个站点的所有表中都使用InnoDB。@egasimus抱歉,我在这一点上被难住了。“DDL语句[…]导致隐式提交。”我知道,MySQL中的DDL不是事务性的,但没有意识到这一含义。谢谢你五年前的今天:)
# db is an example database connection object, which 
#   - supports nested (stacked) transactions, 
#   - has autocommit on.

db.begin() # START TRANSACTION
try:
  # no-conflict op
  db.update() 

  db.begin() # SAVEPOINT sp1
  try:
    # conflict op, 
    # e.g. attempt to change exclusively locked rows by another transaction
    db.update() 

    db.commit() # RELEASE SAVEPOINT sp1
  except:
    # Everything interesting happens here:
    #   - the change attempt failed with OperationalError: (1213, 'Deadlock...'),
    #   - the transaction is rolled back with all the savepoints,
    #   - next line will attempt to rollback to savepoint which no longer exists,
    #   - so will raise OperationalError: (1305, 'SAVEPOINT sp1 does not exist'),
    #   - which will shadow the original exception.

    db.rollback() # ROLLBACK TO SAVEPOINT sp1
    raise

  db.commit() # COMMIT 
except:
  db.rollback() # ROLLBACK
  raise