3

代码很简单,如下:

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()

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

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

我不确定这是否是一个设计决定。我是否必须在每次分配前检查我的输入值是否更改?或者我能做些什么来避免这个恼人的异常?

我的小马版本:0.4.8

非常感谢~~~

4

1 回答 1

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

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

UPDATE MyTable
SET x = <new_value>
WHERE id = 123 and x = <old_value>

您可能想知道,为什么要添加这个附加条件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 。谢谢你的问题!

于 2013-11-16T17:56:49.507 回答