我需要以一种不会默默破坏基于 Web 的应用程序中另一个客户端的更改的方式更新 Oracle 数据库中的行。
在我当前的系统中,我执行以下操作:
SELECT * FROM table WHERE id=:ID AND lastmodified=:LASTMOD
如果该行仍然存在,并且在我们开始时具有相同的上次修改日期,我们就知道没有人更改它,因此我们可以使用上次修改时间进行更新。
然而,当使用两个会话手动执行此操作时,我注意到如果两个客户端大致同时选择,则可能会错过选择和更新步骤之间的行已更改,因为两者都发生在同一秒或同一毫秒内。
最终结果是我破坏了其他用户的更改,并且没有任何警告表明发生了这种情况。
我正在考虑使用 SELECT FROM UPDATE 但显然这是一个bad idea http://www.dba-oracle.com/t_select_for_update.htm(特别是对于网络应用程序),该文章建议重新阅读(这就是我上面所做的),但我仍然认为我面临竞争条件的风险。
Edit:明确表示我担心时间的引用方式。
我假设你的UPDATE
声明本身正在验证lastmodified
您在中读到的值SELECT
正如九边所暗示的那样。
If lastmodified
is a DATE
,那么如果自某个时刻以来同一秒内对同一行进行多次更新,则存在潜在的竞争条件DATE
仅具有秒级的粒度。如果lastmodified
is a TIMESTAMP
,另一方面,竞争条件可能发生的窗口要有限得多,因为TIMESTAMP
将具有 3 到 9 位的亚秒精度(在大多数 Windows 机器上为 3 位,在大多数 Unix 机器上为 6 位)。在同一毫秒甚至同一微秒内进行两次更新的可能性很小,但并非不可能。但这并不是绝对正确的。
您可以使用序列生成的值而不是上次修改日期。这可以保证您不会丢失更新,因为 NOCYCLE 序列不会两次返回相同的值。但是,如果您沿着这条路走下去,您要么会失去每行都有最后更新日期的信息优势,要么会在表的每一行中存储一些额外的数据字节。根据您的应用程序,这些权衡中的任何一个可能都是值得的,或者可能会产生比解决的问题更多的问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)