對需要經(jīng)常并發(fā)操作的表翎冲,sqlalchemy可以加鎖保證數(shù)據(jù)一致性,with_lockmode('update')
:
with_lockmode(mode) 可選mode參數(shù)說明:
mode 參數(shù) | 說明 |
---|---|
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秒后重新執(zhí)行。調(diào)用方法是作為db函數(shù)的注釋標(biāo)簽叶堆。
@functools.wraps(f)和functools.update_wrapper(wrapped, f)是為了讓被注釋的方法保持 __name__ 和 __doc__ 等屬性阱飘,相關(guān)介紹參考 《Python-進(jìn)階-functools模塊小結(jié)》