并发/同步问题

问题描述:

我有2个程序在2个不同的机器上运行。
每个程序都有一个名为updateRecord方法,做以下两两件事:
1.执行某条记录ž
2. SELECT查询请在相同的记录一个UPDATE查询。并发/同步问题

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

即,以下操作顺序失败成功执行?

  1. PROG-1 SELECT
  2. PROG-2 SELECT
  3. PROG-1 UPDATE
  4. PROG-2 UPDATE

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
+0

已更新标签..... – user855 2009-11-27 07:06:16

+0

如果您真的关心并发性,请使用整数数据类型实现版本列。然后确保您的更新/删除语句使用该值来确保您处理最新的记录。 – 2009-11-27 21:53:15

两台机器永远不会使用相同的交易。如果在存储过程中执行SELECT & UPDATE,它们将在同一个事务中。如果SELECT & UPDATE查询是作为单独的语句运行,那么下面的可能性:

  1. PROG-1 SELECT
  2. PROG-2 SELECT
  3. PROG-1 UPDATE
  4. PROG-2 UPDATE

根据数据库隔离级别,机器#2的select可能在运行机器#1的UPDATE之前查看数据。 IIRC,默认情况下Oracle会是这种情况。

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

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

+0

2号机器不使用相同的交易。 我说2个查询是在同一个交易 – user855 2009-11-27 06:59:14

+0

和这个隔离水平如何设置? – user855 2009-11-27 06:59:49

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

+0

锁定发生在数据库中,而不是应用程序。而且有些dbs不支持少列锁。 – 2009-11-27 21:51:56

+0

感谢OMG小马 - 我的答案是针对Oracle的。是的,它是锁定行而不是应用程序的数据库 - SELECT FOR UPDATE语法是应用程序向数据库请求锁的方式。 – 2009-11-29 07:41:57

如前所述,使用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),会话2不见值由SESSION1改变,因为他们都不敢承诺。

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