Sqlalchemy add_all() 忽略重复键 IntegrityError

12

我正在向数据库添加一个对象列表entries。有时可能会发生其中一个对象已经存在于数据库中的情况(我对此没有任何控制)。

如果只出现一个IntegrityError,所有事务都将失败,即entries中的所有对象都不会插入到数据库中。

try:
    session.add_all(entries)
    session.commit()
except:
    logger.error(f"Error! Rolling back")
    session.rollback()
    raise
finally:
    session.close()

我期望的行为是:如果在entries中出现IntegrityError,则捕获它并不将该对象添加到数据库中;否则就正常继续(不会失败)。

编辑:我正在使用MySQL作为后端。

2个回答

15

这取决于你使用的后端。

PostgreSQL有一个非常好用的INSERT() ON CONFLICT DO NOTHING语句,你可以在SQLAlchemy中使用:

from sqlalchemy.dialects.postgresql import insert
session.execute(insert(MyTable)
                .values(my_entries)
                .on_conflict_do_nothing())

MySQL有类似的INSERT IGNORE子句,但SQLAlchemy对其支持较少。幸运的是,根据此答案,有一种解决方法,可以使用prefix_with

session.execute(MyTable.__table__
                .insert()
                .prefix_with('IGNORE')
                .values(my_entries))

唯一需要注意的是,my_entries 必须是列到值的映射列表。这意味着[{ 'id': 1, 'name': 'Ringo' }, { 'id': 2, 'name': 'Paul' }, ...]等等。


-1
我找到的解决方案是在添加之前查询数据库。
try:
    instance = session.query(InstancesTable).filter_by(id=entry.id).first()
    if instance:
        return
    session.add(entry)
    session.commit()
except:
    logger.error(f"Error! Rolling back")
    session.rollback()
    raise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接