Работа с дубликатами первичных ключей при вставке в SQLAlchemy (декларативный стиль)

Мое приложение использует сеанс с ограниченной областью действия и декларативный стиль SQLALchemy. Это веб-приложение, и многие вставки в БД выполняются Celery, планировщиком задач.

Как правило, при принятии решения о вставке объекта мой код может сделать что-то вроде следующих строк:

from schema import Session
from schema.models import Bike

pk = 123 # primary key
bike = Session.query(Bike).filter_by(bike_id=pk).first()
if not bike: # no bike in DB
    new_bike = Bike(pk, "shiny", "bike")
    Session.add(new_bike)
    Session.commit()

Проблема здесь в том, что, поскольку многое из этого делается асинхронными рабочими процессами, возможно, что один из них будет наполовину выполнен. вставка Bikeс id=123, в то время как другой проверяет его существование. В этом случае второй рабочий процесс попытается вставить строку с тем же первичным ключом, и SQLAlchemy выдаст IntegrityError.

Я не могу найти хороший способ справиться с этой проблемой, кроме замены Session.commit()на:

'''schema/__init__.py'''
from sqlalchemy.orm import scoped_session, sessionmaker
Session = scoped_session(sessionmaker())

def commit(ignore=False):
    try:
        Session.commit()
    except IntegrityError as e:
        reason = e.message
        logger.warning(reason)

        if not ignore:
            raise e

        if "Duplicate entry" in reason:
            logger.info("%s already in table." % e.params[0])
            Session.rollback()

И затем везде, где у меня есть Session .commitТеперь у меня есть schema.commit(ignore=True), где я не возражаю против того, чтобы строка не вставлялась снова.

Мне это кажется очень хрупким из-за проверки строк.Так же, как FYI, когда возникает IntegrityError, это выглядит следующим образом:

(IntegrityError) (1062, "Duplicate entry '123' for key 'PRIMARY'")

Итак, конечно, первичный ключ, который я вставлял, был чем-то вроде Повторяющаяся запись — крутая вещь, тогда Я полагаю, что мог пропустить IntegrityError, которых на самом деле не было из-за дублирования первичных ключей.

Существуют ли какие-либо лучшие подходы, которые поддерживают чистый подход SQLAlchemy, который я использую (в отличие от начала записи операторов в строках и т. д.)

Db — это MySQL (хотя для модульного тестирования я предпочитаю использовать SQLite, и не хотел бы мешать этой возможности какими-либо новыми подходами).

Ура!

37
задан Edwardr 25 April 2012 в 19:34
поделиться