表xxx'上的UPDATE语句'期望更新1行; 0与Zope transactionmanager相匹配

时间:2015-06-10 18:04:07

标签: postgresql sqlalchemy pyramid zope transactionmanager

我正在运行Pyramid + Zope事务管理器+ SQLAlchemy + PostgreSQL。在某些情况下,我在Pyramid Web应用程序上看到UPDATE statement on table 'xxx' expected to update 1 row(s); 0 were matched.错误,这应该是更新数据库中一行的非常简单的视图。由于错误发生在普通视图边界之外且不可重复,因此调试非常棘手。

我想这可能与损坏的数据库连接或事务生命周期有关。但是我不知道如何开始调试系统,所以我问的是什么可能导致这个问题,以及如何解决这样的错误。

Stacktrace (most recent call last): File "pyramid/tweens.py", line 20, in excview_tween response = handler(request) File "pyramid_tm/__init__.py", line 94, in tm_tween reraise(*exc_info) File "pyramid_tm/compat.py", line 15, in reraise raise value File "pyramid_tm/__init__.py", line 82, in tm_tween manager.commit() File "transaction/_manager.py", line 111, in commit return self.get().commit() File "transaction/_transaction.py", line 280, in commit reraise(t, v, tb) File "transaction/_compat.py", line 55, in reraise raise value File "transaction/_transaction.py", line 271, in commit self._commitResources() File "transaction/_transaction.py", line 417, in _commitResources reraise(t, v, tb) File "transaction/_compat.py", line 55, in reraise raise value File "transaction/_transaction.py", line 389, in _commitResources rm.tpc_begin(self) File "/srv/pyramid/trees/venv/lib/python3.4/site-packages/zope/sqlalchemy/datamanager.py", line 90, in tpc_begin self.session.flush() File "sqlalchemy/orm/session.py", line 2004, in flush self._flush(objects) File "sqlalchemy/orm/session.py", line 2122, in _flush transaction.rollback(_capture_exception=True) File "sqlalchemy/util/langhelpers.py", line 60, in __exit__ compat.reraise(exc_type, exc_value, exc_tb) File "sqlalchemy/util/compat.py", line 182, in reraise raise value File "sqlalchemy/orm/session.py", line 2086, in _flush flush_context.execute() File "sqlalchemy/orm/unitofwork.py", line 373, in execute rec.execute(self) File "sqlalchemy/orm/unitofwork.py", line 532, in execute uow File "sqlalchemy/orm/persistence.py", line 170, in save_obj mapper, table, update) File "sqlalchemy/orm/persistence.py", line 692, in _emit_update_statements (table.description, len(records), rows))

classdef ProjectTable
    properties (GetAccess = ?AllProjectTables)
        Value
    end
    methods
        function obj = ProjectTable(val)
            obj.Value = val;
        end
        function r = addTwo(obj)
            r = obj.Value + 2;
        end
    end
end

classdef AllProjectTables
    properties
        Project_Table
    end
    methods
        function obj = AllProjectTables(project_table)
            obj.Project_Table = project_table;
        end
        function r = test(obj)
            r = obj.Project_Table.Value;
        end
    end
end

2 个答案:

答案 0 :(得分:7)

这很有可能是这样的情况:

您有2个请求首先选择一个对象并尝试在数据存储区中更新/删除它,并最终得到一个"竞争条件"。

让我们说你想要做一些事情,比如获取一个对象然后更新它。

如果交易需要一些时间而您没有选择"对于更新"因此锁定行 - 如果在第一个请求中删除了对象,并且第二个事务尝试再向数据库中不存在的行发出更新,则最终会出现此异常。

您可以尝试进行一些行锁定以防止这种情况发生 - 后续事务将等待"等待"第一次完成的操作。在它被执行之前。

http://docs.sqlalchemy.org/en/rel_1_0/orm/query.html?highlight=for_update#sqlalchemy.orm.query.Query.with_for_update

http://docs.sqlalchemy.org/en/rel_1_0/orm/query.html?highlight=with_lockmode#sqlalchemy.orm.query.Query.with_lockmode

描述一些可用于解决此问题的sqlalchemy机器。

答案 1 :(得分:1)

另一种选择:

TL,DR:如果你有"第一个()"在某些情况下,如果更新多个记录,则需要在炼金术中删除它

db.session.query(xxx).filter_by(field=value).first()

此命令期望更新仅影响一行。如果你的表只有一个field = value的记录,那就应该这样。如果字段是您的ID,则尤其如此。

但是 - 如果您的ID未在SQL中定义为唯一,则可能有多个具有相同ID的记录。

在这种情况下你可以更新所有删除" first()"

BTW,使用以下命令调试您的SQL查询(这次没有帮助......)

import logging

logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)