我有2张具有一对多关系的表。
表A | 表B |
---|---|
id | id |
正在运行 | a_id |
正在运行 |
我正在做这样的事情:
交易1 | 交易2 | 交易3 |
---|---|---|
|
|
|
|
|
事务1更新A并获取所有正在运行的相关B。
仅当相关 A 正在运行时,事务 2 才会向 table_b 中插入一行。
事务 3 更新 table_b 中的一行。
我希望有3>1>2这样的优先策略。换句话说:
如果事务 2 检测到事务 1 已提交,则它会回滚。
事务 1 将等待事务 3 提交,以便它选择的行是最新的。
我尝试将事务2中的
SELECT
设置为FOR UPDATE
以确保序列化,但这不符合我的需求,因为事务2在提交事务1时应该被迫回滚。
如果在同一个数据库连接上一个接一个地运行这三个事务,那么严格序列化这三个事务是微不足道的……但这显然不是正在发生的情况,并且这三个事务必须在不同的会话中运行。
如果要序列化它们,则需要协调运行语句的会话。您可以通过不同的方式做到这一点:
从一开始就对受事务影响的所有表采取显式
ACCESS EXCLUSIVE
锁定。
那是愚人之道。它将阻止所有并发访问,如果您经常这样做,您将与 autovacuum 发生冲突,而 autovacuum 永远无法完成表的处理。
采用事务级咨询锁来显式协调事务。
这是一种不错的方法,但您必须显式地对其进行编码。
协调应用程序端的会话。
这也可以很好地工作,但超出了数据库的范围。
使用
SERIALIZABLE
隔离级别。
这是最好的方法。您试图避免的问题是“事务异常”,即在串行执行中永远不会发生的影响。通过SERIALIZABLE
隔离,保证您不会出现异常情况。
,在这种情况下由应用程序重试该交易。
如果这三个事务确实必须以某种确定性的顺序发生,那么您可能真的应该在单个数据库会话中运行它们。