问题描述
我正在尝试为某商品预订订单。但是要做到这一点,我需要能够获取项目并锁定它们,以便在我更新或释放锁之前,阻止其他并发的读写操作。通过使用try-finally块,可以确保调用release的方式。
如何在保持逻辑和数据访问关注点分离的同时阻止对表或某些行的读写?
用例如下:
def use_case(input,repository):
validate_input(input)
try:
data = repository.get_data()
if condition1 and condition2:
update_data()
finally:
repository.unlock()
我实现存储库的方式是:
class Repository:
def get_data():
conn = adapter.connect()
cur = conn.cursor()
cur.execute('select * from table where condition')
cur.close()
conn.close()
def update():
conn = adapter.connect()
cur = conn.cursor()
cur.execute('update table set field = value where condition')
cur.close()
conn.close()
def unlock():
pass
我曾经尝试过选择更新,显式锁定和咨询性锁定,但是当连接关闭时它们都将释放。
我本可以使用乐观锁定,但是问题是我要一次更新多列。而且即使一次列的值发生变化,我也需要重新运行逻辑。
我创建单独连接的原因是为了避免闲置连接,而仅在需要时才创建它们。我不知道这是否是标准的处理方式。
解决方法
本质上有两种选择:乐观锁定和悲观锁定:
-
具有悲观锁定,所有操作都在单个数据库事务内进行。您
SELECT ... FOR UPDATE
,然后通过提交事务来释放锁。如果整个操作很短(无用户交互!),则悲观锁定是好的,尤其是在发生冲突的可能性很高的情况下。
-
乐观锁定不受数据库事务约束(尽管您可以使用
REPEATABLE READ
事务实现)。您会记住所有列的原始值,并将UPDATE
与WHERE
条件一起使用,该条件检查所有值仍然相同(没人修改该行)。如果并发事务修改了该行(未更新任何行),则重复整个操作。如果操作花费很长时间或发生冲突的可能性很小,那么乐观锁定是好的。