SqlAlchemy 完整性错误
我正在尝试从Facebook上获取大量数据,并在处理这些数据时将对象添加到数据库中。比如说,对于点赞,我只是把点赞者的ID作为记录。但是,当我添加多个点赞时,就会遇到一个问题,叫做完整性错误,因为主键不唯一。
那么,处理这个问题的最佳方法是什么呢?我每次要添加新的点赞到数据库时,都需要查询一下,看看这个点赞是否已经存在,如果存在就增加它的计数,如果不存在就创建一个新的记录吗?
这样听起来是不是要进行很多次查询?你觉得最好的做法是什么呢?
1 个回答
6
你真的需要为了应对高负载而进行优化吗?可能不需要,因为你在使用SQLite。在这种情况下,简单的解决方案要好得多:
class Like(Base):
__tablename__ = 'Like'
id = Column(Integer, primary_key=True)
counter = Column(Integer, nullable=False, default=0)
o = session.merge(Like(id=1))
session.flush() # Required when it's new record
o.counter = Like.counter+1
session.commit()
在检查和插入之间存在一个竞争条件,但我相信在实际操作中这不会对你造成太大影响。
当你真的需要稍微优化一下或者修复这个竞争条件时,SQLite中有一个 INSERT OR IGNORE
的方法,可以避免检查(这里实际上执行了两个独立的语句):
clause = Like.__table__.insert(prefixes=['OR IGNORE'],
values=dict(id=1, counter=0))
session.execute(clause)
o = session.merge(Like(id=1, counter=Like.counter+1))
session.commit()
最后,还有一种方法可以用单个语句来完成,使用 INSERT OR REPLACE
和子查询(在大多数其他数据库中也有类似的方法,比如MySQL中的 ON DUPLICATE KEY
),但我怀疑这会给你带来明显的性能提升:
old = session.query(Like.counter).filter_by(id=1).statement.as_scalar()
new = func.ifnull(old, 0) + 1
clause = Like.__table__.insert(prefixes=['OR REPLACE'],
values=dict(id=1, counter=new))
session.execute(clause)