并发/同步问题

时间:2009-11-27 06:50:21

标签: mysql database oracle locking

我在2台不同的机器上运行了2个程序。
每个程序都有一个名为updateRecord的方法,它执行以下两项操作:
1.对特定记录执行SELECT查询Z
2.对同一记录执行UPDATE查询。

如果这两个查询在同一个事务中(beginTransaction和commitTransaction之间),它是否保证正确执行?

即,以下操作序列失败会成功执行吗?

  1. Prog-1 SELECT
  2. Prog-2 SELECT
  3. Prog-1 UPDATE
  4. Prog-2 UPDATE
  5. OR

    1. Prog-1 SELECT
    2. Prog-1 UPDATE
    3. Prog-1 SELECT
    4. Prog-2 UPDATE
    5. Prog-1 COMMIT
    6. Prog-2 COMMIT

3 个答案:

答案 0 :(得分:3)

您的程序在选择记录时需要锁定记录 - 例如使用SELECT FOR UPDATE语法。这样,记录将被锁定,直到UPDATE完成。

答案 1 :(得分:2)

如前所述,使用SELECT ... FOR UPDATE有助于锁定行,直到提交(或回滚)事务为止。

您不需要两台机器来测试它。通过使用两个不同的会话(例如,通过运行两个不同的SQL * Plus实例)并在两个会话上以特定顺序同时运行查询,您将能够重现并发问题(如果有)。

在这种情况下,你可以运行:

Session1: SELECT z AS sel_z -- sel_z = 0
Session1: UPDATE z = sel_z + 1
Session2: SELECT z AS sel_z -- (1) sel_z = 0 because Session1 is uncommitted
Session2: UPDATE z = sel_z + 1
Session1: COMMIT
Session2: COMMIT
Session1: SELECT z AS sel_z -- sel_z = 1
Session2: SELECT z AS sel_z -- sel_z = 1

问题出在(1),Session2没有看到Session1改变的值,因为它们没有被提交。

我的建议是不要考虑改变TX隔离级别,考虑锁定适当的资源。

答案 2 :(得分:1)

两台机器永远不会使用相同的交易。如果SELECT& UPDATE在存储过程中执行,它们将在同一事务中。如果SELECT& UPDATE查询作为单独的语句运行,然后可能出现以下情况:

  1. Prog-1 SELECT
  2. Prog-2 SELECT
  3. Prog-1 UPDATE
  4. Prog-2 UPDATE
  5. 根据数据库隔离级别,机器#2的选择可能是在运行机器#1的UPDATE之前查看数据。 IIRC,默认情况下就是这种情况。

    这是411 on Oracle's Isolation Levels, per AskTom

    对于MySQL,请使用SET TRANSACTION命令。有关MySQL隔离级别支持的更多信息,请参阅this link