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
在 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