我的应用程序正在使用作用域会话和SQLALchemy的声明式样式。这是一个web应用程序,许多数据库插入由Celery
执行,一个任务调度程序。在插入SQLAlchemy(声明式)时处理重复的主键
通常情况下,决定插入的对象时,我的代码可能会做大致如下的内容:
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
,而另一个正在检查其存在,但工作中途中断。在这种情况下,第二个worker将尝试使用相同的主键插入一行,并且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,并不想用任何新方法来阻止这种能力)。
干杯!
你为什么不考虑使用自动递增为您生成主键?那么你不必担心这个问题。 还是有没有这样做的具体原因? – mata 2012-04-25 19:40:39
有一个特定的原因(对不起,这个例子有点琐碎)。 – Edwardr 2012-04-25 19:50:37