Oracle - 如何防止多个进程更新同一行?

Oracle - How to prevent multiple multiple processes from updating same row?

在 Oracle 中,有没有办法让另一个进程正在读取数据库行 "locked"?我遇到的一个问题是,有时如果两个进程尝试访问同一个数据库行并同时更新它,其中一个更新可能会丢失。

这是正在发生的事情的基本时间图。

Process #1              Process #2
------------------      ------------------
Read from Database
Some processing...      Read from database
Some processing...      Some processing...
Update database         Some processing...
                        Update database

在上面的示例中,进程 #1 的更新丢失,因为进程 #2 在进程 #2 完成更新之前从数据库中读取。

我已经修改了代码(用 C++ 编写,但我不确定这对这个问题是否真的很重要)以最小化读取数据库和写入数据库之间发生的处理量(例如读取在尽可能晚的时间从数据库中获取,只做我们需要做的确切处理量,然后立即更新),这有助于缓解这个问题,但仍然不能保证它是一个防弹修复。

我可以修改代码,让进程 #2 告诉进程 #1 用什么更新数据库,让进程 #1 处理与数据库的所有交互,但不幸的是,在我的情况下,有几十个进程和数据库我正在处理的表格,所以我不确定这样的更改是否可行。

是否可以在数据库中执行任何操作来防止出现此问题?

您可以使用 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Window 1:

SQL> SET TRANSACTION ISOLATION
  2  LEVEL SERIALIZABLE;

Transaction set.

Window 2:

SQL> SET TRANSACTION ISOLATION
  2  LEVEL SERIALIZABLE;

Transaction set.

Window 1:

SQL> select * from test;

no rows selected

SQL> insert into test values (1);

1 row created.

SQL> commit;

Commit complete.

Window 2:

SQL> select * from test;

no rows selected

即使您插入了一行并在 Window 1 中提交了它,它在 Window 2 中也看不到。隔离级别可序列化是有风险的,因为它可能会导致很多不需要的锁定。

您可以在查询中使用 FOR UPDATE 子句。

有关此子句的更多详细信息,请参阅此 link:https://www.techonthenet.com/oracle/cursors/for_update.php

另请检查下面的问题,了解一些使用 FOR UPDATE 的示例代码。

Link: How to use Oracle DB sequences without losing the next sequence number in case of roll-back