私のアプリケーションは、スコープセッションとSQLALchemyの宣言型スタイルを使用しています。これはWebアプリであり、多くのDB挿入は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
withを挿入しても途中で動作しid=123
、別の作業がその存在を確認している可能性があることです。この場合、2番目のワーカーは同じ主キーを持つ行を挿入しようとし、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)
行が再び挿入されなくてもかまわない場所があります。
文字列チェックのため、これは非常に脆弱に思えます。参考までに、IntegrityError
を上げると次のようになります。
(IntegrityError) (1062, "Duplicate entry '123' for key 'PRIMARY'")
ですからもちろん、私が挿入していた主キーは次のようなものでした。主キーが重複しているために実際にはそうではなかったものをDuplicate entry is a cool thing
見逃す可能性があると思います。IntegrityError
私が使用しているクリーンなSQLAlchemyアプローチを維持するより良いアプローチはありますか(文字列などでステートメントを書き始めるのとは対照的です。..)
DbはMySQLです(ユニットテストではSQLiteを使用するのが好きで、新しいアプローチでその機能を妨げたくありません)。
乾杯!