对需要经常并发操作的表,sqlalchemy可以加锁保证数据一致性,with_lockmode('update')
:
with_lockmode(mode) 可选mode参数说明:
mode 参数 | 说明 |
---|---|
None | translates to no lockmode |
'update' | translates to FOR UPDATE (standard SQL, supported by most dialects) |
'update_nowait' | translates to FOR UPDATE NOWAIT (supported by Oracle, PostgreSQL 8.1 upwards) |
'read' | translates to LOCK IN SHARE MODE (for MySQL), and FOR SHARE (for PostgreSQL) |
def _get_quota_usages(context, session, project_id):
# Broken out for testability
rows = model_query(context, models.QuotaUsage,
read_deleted="no",
session=session). \
filter_by(project_id=project_id). \
order_by(models.QuotaUsage.id.asc()). \
with_lockmode('update'). \
all()
return {row.resource: row for row in rows}
cinder dbapi里处理死锁的方法,_retry_on_deadlock(f)
def _retry_on_deadlock(f):
"""Decorator to retry a DB API call if Deadlock was received."""
@functools.wraps(f)
def wrapped(*args, **kwargs):
while True:
try:
return f(*args, **kwargs)
except db_exc.DBDeadlock:
LOG.warning(_LW("Deadlock detected when running "
"'%(func_name)s': Retrying..."),
dict(func_name=f.__name__))
# Retry!
time.sleep(0.5)
continue
functools.update_wrapper(wrapped, f)
return wrapped
@require_context
@_retry_on_deadlock
def reservation_commit(context, reservations, project_id=None):
<!--代码省略-->
_retry_on_deadlock(f)
逻辑简单,即抓到死锁异常db_exc.DBDeadlock,则过0.5秒后重新执行。调用方法是作为db函数的注释标签。
@functools.wraps(f)和functools.update_wrapper(wrapped, f)是为了让被注释的方法保持 __name__ 和 __doc__ 等属性,相关介绍参考 《Python-进阶-functools模块小结》
网友评论