在插入 Python 之前进行 SQLAlchemy 检查

doh*_*nto 4 python sqlalchemy exception race-condition

我有一个关于如何检查条目是否已经在数据库表中的更合适/更有效的方法的问题。

假设我有一个Foo用单个属性调用的表,Name它也是unique。

如果已经存在具有此类名称的条目,在插入之前检查的更好方法是什么?我可以想到两种选择:

from sqlalchemy import MetaData, Table, Column, String, \
create_engine
from sqlalchemy.orm import mapper, relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import IntegrityError

Base = declarative_base()

class Foo(Base):
    __tablename__ = "foo"

    name = Column(String(), primary_key=True)

    @staticmethod
    def silent_insert1(name):
            if not session.query(Foo).filter(Foo.name == name).first():
                    foo = Foo()
                    foo.name = name
                    session.add(foo)
                    session.commit()
            else:
                    print("already exists 1")

    @staticmethod
    def silent_insert2(name):
            try:
                    foo = Foo()
                    foo.name = name
                    session.add(foo)
                    session.commit()
            except(IntegrityError):
                    print("already exists 2")


engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
session = sessionmaker(engine)()

Foo.silent_insert1(1)
Foo.silent_insert2(1)
Run Code Online (Sandbox Code Playgroud)

在第一个silent_insert1 中,当然存在竞争条件。第二个似乎更防弹。

哪一个更好?是否有更好的方法或推荐的方法来检查这个?

谢谢

Jor*_*ley 10

你应该只把session.add在try/except

其次,这是一个哲学问题。你不会得到一个明确的答案。

这两种风格被称为跳前先看(LBYL),这种风格提前使用 if 语句来判断你是否应该这样做。

第二种风格被称为更容易要求宽恕,而不是 Permission(EAFP),这种风格假设它可以工作并捕获和处理在违反规则的情况下引发的异常。作为一般规则,python 程序员倾向于支持 EAFP,但与任何规则一样,也有许多例外

  • 我认为您还需要在 `try` 之前使用 `session.flush`,以确保在块开始之前会引发任何先前的错误。 (3认同)