Sqlalchemy 添加多条记录和潜在的约束违规

Ale*_*.P. 2 python sqlalchemy

我有一列具有独特约束的表,例如:

CREATE TABLE entity (
    id      INT NOT NULL AUTO_INCREMENT,
    zip_code    INT NOT NULL,
    entity_url  VARCHAR(255) NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY ix_uniq_zip_code_entity_url (zip_code, entity_url)
);
Run Code Online (Sandbox Code Playgroud)

和相应的 SQLAlchemy 模型。我添加了很多记录,不想在每条记录后提交会话。我的假设更好地调用session.add(new_record)多次和一次session.commit()

但是在添加新记录时我可能会IntegrityError因为违反约束而得到。这是正常情况,我只想跳过此类记录插入。但看起来我只能恢复整个交易。

此外,我不想添加另一个复杂的检查“从数据库中获取所有记录,其中 zip_code in [...] 和 entity_url in [...] 然后从 records_to_insert 中删除匹配的数据”。

有没有办法指导 SQLAlchemy 删除违反约束的记录?

小智 5

我的假设更好地调用session.add(new_record)多次和一次session.commit()

您可能想要重新审视这个假设。大量记录的批处理通常适用于多次提交——如果您有 10k 条记录并且您的代码在第 9,999 次引发异常怎么办?你将被迫重新开始。这里的核心问题是数据库中存在一条记录而没有其他记录是否有意义。如果是这样,那么在每个条目上提交都没有问题(性能问题除外)。在这种情况下,您可以简单地捕获 IntegrityError 并调用session.rollback()以继续向下记录列表。

无论如何,在 SQLA 邮件列表上提出了一个类似的问题,并由库的创建者 Mike Bayer 回答。他建议您自己从新记录列表中删除重复项,因为使用字典或集合很容易做到这一点。这可以像字典理解一样简单:

new_entities = { (entity['zip_code'], entity['url']): entity for entity in new_entities}
Run Code Online (Sandbox Code Playgroud)

(这将选择最后看到的副本作为添加到数据库的副本。)

还要注意,他使用 SQLAlchemy 核心库来执行插入,而不是 ORM 的session.add()方法:

sess.execute(Entry.__table__.insert(), params=inserts)
Run Code Online (Sandbox Code Playgroud)

如果您要处理大量记录(例如在他的示例中,有 100,000 条记录),这是一个更快的选择。