我想请你帮忙解决我的问题。我有一个程序,它可以并行触发异步计算,并在循环中等待,直到它们完成。
我使用Postgres作为数据库,在其中创建了表computation_status
,当计算被触发时,该表包含以下数据:
| 计算|完成的|
| - ------|- ------|
| 计算_A|零|
| 计算_B|零|
| 计算_C|零|
然后,我在循环中等待,直到所有计算完成。此循环接受每个已完成计算的通知,并触发SQL事务更新其状态,检查是否有任何其他计算正在运行。例如:
T1:
BEGIN_TRANSACTION
update computation_status set finished = NOW() where and computation = 'COMPUTATION_A'
select exists (select 1 from computation_status where finished is null)
COMMIT
T2:
BEGIN_TRANSACTION
update computation_status set finished = NOW() where and computation = 'COMPUTATION_B'
select exists (select 1 from computation_status where finished is null)
COMMIT
T3:
BEGIN_TRANSACTION
update computation_status set finished = NOW() where and computation = 'COMPUTATION_C'
select exists (select 1 from computation_status where finished is null)
COMMIT
当最后一次计算完成时,程序退出等待循环。
我应该使用什么级别的隔离来避免这些问题?我知道我至少应该使用READ_COMMITED隔离级别来防止不可重复的读取,但这足够了吗?或者,是否也有可能发生幻像读取,我应该使用REPETABLE_READ?(我不确定UPDATE是否也算作READ)。
我想避免这样的问题,例如计算A和B将在最后一个同时完成,然后T1将设置A=finished并读取B未完成,T2将设置B=finished并读取A未被钓鱼,这将导致我的应用程序出现问题,因为它将以无限循环结束。
1条答案
按热度按时间11dmarpk1#
为了避免出现争用情况,必须有效地序列化事务。
唯一能可靠工作的隔离级别是
SERIALIZABLE
。但是,这会导致性能损失,并且您必须准备好在引发序列化错误时重复事务。如果并发运行多个这样的事务,则会引发序列化错误。另一种选择是使用锁,但这不是很有吸引力:使用行锁会导致死锁,而使用表锁会阻塞autovacuum,这最终会使系统崩溃。