Sqlalchemy add_all() 忽略重复键 IntegrityError

dra*_*dog 13 python mysql sqlalchemy

我正在将对象列表添加entries到数据库中。有时可能会发生这些对象之一已经在数据库中的情况(我对此没有任何控制权)。如果只有一个,IntegrityError所有事务都会失败,即所有对象都entries不会被插入到数据库中。

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

我期望的行为是:如果IntegrityError其中一个中有 a entries,则捕获它并且不将该对象添加到数据库中,否则正常继续(不要失败)

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

Rub*_*oot 16

我取决于你使用的后端。

PostgreSQL有一个很棒的INSERT() ON CONFLICT DO NOTHING子句,您可以将其与 SQLAlchemy 一起使用:

from sqlalchemy.dialects.postgresql import insert
session.execute(insert(MyTable)
                .values(my_entries)
                .on_conflict_do_nothing())
Run Code Online (Sandbox Code Playgroud)

MySQL也有类似的INSERT IGNORE子句,但是SQLAlchemy对它的支持较少。幸运的是,根据这个答案,有一个解决方法,使用prefix_with

session.execute(MyTable.__table__
                .insert()
                .prefix_with('IGNORE')
                .values(my_entries))
Run Code Online (Sandbox Code Playgroud)

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