并发/同步问题
我有2个程序在2个不同的机器上运行。
每个程序都有一个名为updateRecord方法,做以下两两件事:
1.执行某条记录ž
2. SELECT查询请在相同的记录一个UPDATE查询。并发/同步问题
如果这两个查询在同一个事务中(在beginTransaction和commitTransaction之间)它确保正确执行吗?
即,以下操作顺序失败成功执行?
- PROG-1 SELECT
- PROG-2 SELECT
- PROG-1 UPDATE
- PROG-2 UPDATE
OR
- PROG-1 SELECT
- Prog-1 UPDATE
- PROG-1 SELECT
- PROG-2 UPDATE
- PROG-1 COMMIT
- PROG-2 COMMIT
两台机器永远不会使用相同的交易。如果在存储过程中执行SELECT & UPDATE,它们将在同一个事务中。如果SELECT & UPDATE查询是作为单独的语句运行,那么下面的可能性:
- PROG-1 SELECT
- PROG-2 SELECT
- PROG-1 UPDATE
- PROG-2 UPDATE
根据数据库隔离级别,机器#2的select可能在运行机器#1的UPDATE之前查看数据。 IIRC,默认情况下Oracle会是这种情况。
这是411 on Oracle's Isolation Levels, per AskTom。
对于MySQL,请使用SET TRANSACTION
命令。有关MySQL隔离级别支持的更多信息,请参阅this link。
当程序选择它时,程序需要锁定记录 - 例如,使用SELECT FOR UPDATE语法。这样,记录将被锁定,直到UPDATE完成。
锁定发生在数据库中,而不是应用程序。而且有些dbs不支持少列锁。 – 2009-11-27 21:51:56
感谢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隔离级别,考虑锁定适当的资源。
已更新标签..... – user855 2009-11-27 07:06:16
如果您真的关心并发性,请使用整数数据类型实现版本列。然后确保您的更新/删除语句使用该值来确保您处理最新的记录。 – 2009-11-27 21:53:15