【问题标题】:Implement pessimistic locking实现悲观锁定
【发布时间】:2012-07-30 14:07:51
【问题描述】:

我对如何以非常具体的行为实现悲观锁定很感兴趣。 (我用 Sybase+Oracle+MSSQL 标记问题的原因是因为我很高兴有一个解决方案或“这是不可能的!”对于其中任何一个)

我想要的是: 1 - 能够锁定一行(以便该进程稍后可以进行更新,但没有其他进程可以锁定该行) 2 - 当另一个进程尝试锁定同一行时,它应该收到记录被锁定的通知 - 我不希望这个进程挂起(我相信可以在这里使用简单的超时) 3 - 当另一个进程尝试读取记录时,它应该能够以当前在数据库中的方式读取它(但我不想使用脏读)。

目前,应用程序使用共享内存解决了上述 3 个要求 - 并在数据库外部执行记录锁定。我想将锁定移动到数据库中。

到目前为止,我在 #1 和 #3 之间存在冲突 - 如果我通过将字段更新为相同值来执行“更新 ...”来锁定记录,那么来自另一个进程的“选择”会挂起。

编辑: 我现在对 MSSQL 上的快照隔离级别有一些运气。我可以在不使用脏读的情况下同时进行锁定和读取。

我不想使用脏读的原因是,如果报表正在运行,它可能会读取多个表并发出多个查询。快照为我提供了数据库的一致快照。如果是脏读,我会得到不匹配的数据——如果中间有任何更新的话。

我认为 Oracle 也有快照,所以现在我对 Sybase 最感兴趣。

【问题讨论】:

  • 你能详细解释一下为什么你不想使用脏读吗?这就是您在 #3 中要求的定义。

标签: sql-server oracle sap-ase


【解决方案1】:

在 Oracle 中,您可以使用 select for update nowait 来锁定记录。

select * from tab where id=1234 for update nowait;

如果另一个进程尝试执行相同的语句,则会出现异常:

ORA-00054: resource busy and acquire with NOWAIT specified

直到第一个进程(会话)执行提交或回滚。

通常,oracle 不允许脏读

【讨论】:

    【解决方案2】:

    您描述的 #1 和 #3 之间的冲突是合乎逻辑的:您可以让数据库执行脏读或阻止读取。如果您可以读取锁定的行,则根据定义,它是脏读。这与您使用的特定数据库系统无关!

    因此,如果您希望这样:是的,所有 3 个系统都无法实现您想要的,因为它损害了“脏读”的定义。

    【讨论】:

    • #1 和#3 之间没有内在冲突。这就是 Oracle 的多版本读取一致性在默认情况下所做的。它禁止脏读,防止写入者阻塞读取器,并防止写入器阻塞读取器。 SQL Server 的快照隔离级别提供了类似的功能。
    • @JustinCave 是的,有一个冲突:他希望在#3 中“能够以当前在数据库中的方式读取它”,但没有脏读。但是读取锁定的元素是脏读 - 授予:不是根据定义;但从逻辑上讲,实现不会阻止任何事情的锁定功能是没有意义的。我说的对吗?
    • 快照是我想我要找的。它锁定了作者,但不锁定读者。您引用的我的陈述不是很好,但快照确实允许我读取一致的数据,即使它不是“数据库中的当前内容”,它对于某些特定时间片也是一致的。
    猜你喜欢
    • 2012-11-08
    • 1970-01-01
    • 2010-09-12
    • 2013-12-07
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多