Pony ORM报告记录"在当前交易之外更新",而没有其他交易

Kur*_*Rao 3 python orm transactions ponyorm

代码非常简单,如下所示:

from pony.orm import Required, Set, Optional, PrimaryKey
from pony.orm import Database, db_session
import time


db = Database('mysql', host="localhost", port=3306, user="root",
                      passwd="123456", db="learn_pony")


class TryUpdate(db.Entity):
    _table_ = "try_update_record"
    t = Required(int, default=0)

db.generate_mapping(create_tables=True)


@db_session
def insert_record():
    new_t = TryUpdate()


@db_session
def update():
    t = TryUpdate.get(id=1)
    print t.t
    t.t = 0
    print t.t


if __name__ == "__main__":
    insert_record()
    update()
Run Code Online (Sandbox Code Playgroud)

pony.orm报告异常:pony.orm.core.CommitException:对象TryUpdate [1]在当前事务之外更新.但是根本没有其他交易在运行

正如我的实验所示,只要tt更改为与原始值不同的值,pony就可以正常工作,但是当tt设置为等于原始值的值时,它总是会报告异常.

我不确定这是否是一个设计决定.在分配之前,我是否必须检查输入值是否每次都在变化?或者我有什么办法可以避免这个烦人的异常?

我的小马版:0.4.8

Thansk很多~~~

Ale*_*sky 8

Pony ORM的作者在这里.

此行为是特定于MySQL的错误,已在发布Pony ORM 0.4.9中修复,因此请升级.我的答案的其余部分是解释导致错误的原因.

这个错误的原因如下.为了防止丢失更新,Pony ORM使用乐观检查.Pony跟踪在程序执行期间读取或更改的属性,然后WHERE在相应UPDATE查询的部分中添加额外条件.这样,Pony保证不会因为并发更新而丢失任何数据.让我们考虑下一个例子:

@db_session
def some_function()
   obj = MyObject[123]
   print obj.x
   obj.x = 100
Run Code Online (Sandbox Code Playgroud)

在出口处some_function@db_session装饰将提交正在进行中的事务.在提交之前,对象的数据将通过以下UPDATE命令保存:

UPDATE MyTable
SET x = <new_value>
WHERE id = 123 and x = <old_value>
Run Code Online (Sandbox Code Playgroud)

您可能想知道为什么and x = <old_value>添加这个附加条件?这是因为Pony知道程序看到了属性的先前值,x并且可能使用此值来计算相同属性的新值.因此,Pony采取措施保证此属性在此时保持不变UPDATE.这种方法称为"乐观并发检查"(另请参阅维基百科文章"乐观并发控制").由于大多数数据库中默认使用的隔离级别不是SERIALIZABLE,如果没有这个额外的检查,可能是某些其他事务x在我们的事务提交之前设法更新了属性的值,然后并发事务写入的值将丢失.

当Python数据库驱动程序执行UPDATE查询时,它返回满足UPDATE条件的行数.这样Pony知道更新是否成功.如果结果为1,则表示已成功找到并更新了一行,但如果结果为0,则表示该行已被另一个事务修改,现在它不满足该WHERE部分中的条件.当发生这种情况时,Pony会终止当前事务以防止丢失更新.

该错误的原因是,虽然所有其他数据库驱动程序返回按WHERE部分条件找到的行数,但MySQLdb默认情况下驱动程序返回实际修改的行数!因此,如果属性的新值与同一属性的原始值相同,则MySQLdb报告修改了0行,而Pony(在版本0.4.9之前)错误地认为它意味着该行由并发事务修改.从0.4.9开始,Pony ORM告诉MySQLdb驱动程序以标准方式运行并返回找到的行数而不是实际更新的行数.

希望这可以帮助 :)

PS我发现你只是偶然的问题,为了可靠地得到关于Pony ORM的答案,我建议你把问题发送到我们的邮件列表http://ponyorm-list.ponyorm.com.如果您认为您发现了一个错误,可以在此处打开问题:https://github.com/ponyorm/pony/issues.谢谢你的问题!