python - sqlalchemy 完整性错误

标签 python sqlalchemy

我有一个表,其中主键(id)不是我区分记录的键。为此,我对 3 列有一个唯一的约束。 为了能够合并记录,我添加了一个类方法,用于检索相关记录(如果存在),否则返回一条新记录。

class Foo(Base):
    __table_args__ = (sa.UniqueConstraint('bar', 'baz', 'qux'),)

    id = sa.Column(Identifier, sa.Sequence('%s_id_seq' % __tablename__), nullable=False, primary_key=True)
    bar = sa.Column(sa.BigInteger)
    baz = sa.Column(sa.BigInteger)
    qux = sa.Column(sa.BigInteger)
    a1 = sa.Column(sa.BigInteger)
    a2 = sa.Column(sa.BigInteger)

    @classmethod
    def get(cls, bar=None, baz=None, qux=None, **kwargs):
        item = session.query(cls).\
            filter(cls.bar== bar).\
            filter(cls.baz == baz).\
            filter(cls.qux == qux).\
            first()

        if item:
            for k, v in kwargs.iteritems():
                if getattr(item, k) != v:
                    setattr(item, k, v)
        else:
            item = cls(bar=bar, baz=baz, qux=qux, **kwargs)

        return item

这在大多数情况下都有效,但每隔一段时间,我在尝试合并项目时会收到​​完整性错误:

foo = Foo.get(**item)
session.merge(foo)

据我了解,发生这种情况是因为合并尝试插入一条记录,其中已存在具有唯一字段的记录。

get 函数有问题吗?我在这里缺少什么?

(顺便说一句:我意识到这可能看起来很尴尬,但我需要一个唯一的顺序ID,并且为了避免数据库不支持非主键列上的序列的问题,我这样做了)

编辑 1: 将 orm.db 更改为 session,这样示例会更清晰

编辑 2: 我有这个系统在多个平台上运行,似乎这只发生在 Ubuntu 之上的 mysql 中(其他平台是 RedHat 之上的 Oracle)。此外,以某种奇怪的方式,这种情况更多地发生在特定的最终用户身上。 关于mysql,我尝试了mysql和mysql+mysqldb作为连接字符串,但都产生了这个错误。 对于最终用户来说,这是没有意义的,我不知道该怎么做...... 关于mysql,

最佳答案

事实上,您的方法很容易出现完整性错误。发生的情况是,当您调用 Foo.get(1,2,3) 2 次时,您不会刷新其间的 session 。第二次调用它时,ORM 查询再次失败 - 因为数据库中还没有实际行 - 并且创建了一个具有不同标识的新对象。然后在提交/刷新时这两个冲突导致完整性错误。这可以通过在每次对象创建后刷新数据库来避免。

现在,如果在合并/ORM get 中已知主键,则 SQLAlchemy 中的工作方式会有所不同 - 如果发现匹配的主键已在 session 中加载,SQLAlchemy 意识到这两个必须是同一对象。但是,不会对唯一索引进行此类检查。或许也可以这样做。然而,这只会使竞争条件变得更加罕见,因为可能有 2 个 session 同时创建相同的(bar、baz、qux)三元组。

TL;博士:

else:
    item = cls(bar=bar, baz=baz, qux=qux, **kwargs)
    session.add(item)
    session.flush()

关于python - sqlalchemy 完整性错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18030857/

相关文章:

python - 计算两个角度之间的差异

Python查找字符串并替换

sql - 在多个表中存储数据值与通过查询访问相同的值

Python SQLAlchemy 获取匹配行和列相同的下一行

python - SQL炼金术 : is there any good automated way to rename columns

Python 库 pdfplumber 不提取行

python - 我如何构建动态查询elasticsearch dsl python

python - 如何在不使用pygame的情况下检测按键事件和按键按下事件

Python SQL 炼金术 : table with no primary keys and duplicate values?

python - 如何在 Python 中通过 API 查询在 SQL Alchemy 中插入关系数据(多对多)