我的应用程序使用范围会话和 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()
这里的问题是,因为其中很多工作是由异步工作人员完成的,所以一个工作可能在插入 a Bike
with时工作到一半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)
我不介意不再插入该行的地方。
对我来说,由于字符串检查,这似乎很脆弱。仅供参考,当 anIntegrityError
被提出时,它看起来像这样:
(IntegrityError) (1062, "Duplicate entry '123' for key 'PRIMARY'")
所以当然是我插入的主键是Duplicate entry is a cool thing
我想我可能会错过IntegrityError
的东西,这实际上并不是因为重复的主键。
有没有更好的方法来保持我正在使用的干净的 SQLAlchemy 方法(而不是开始在字符串中写出语句等......)
Db 是 MySQL(尽管对于单元测试,我喜欢使用 SQLite,并且不想用任何新方法阻碍这种能力)。
干杯!