在Oracle中实现乐观锁定

时间:2016-12-06 23:40:24

标签: java oracle locking

我对Oracle中锁定的主题感到困惑。就我的研究引导我而言,您可以使用FOR UPDATE NOWAIT/WAIT锁定行。

我想以这种方式实现我的锁定。一旦我发出FOR UPDATE,该行就会被锁定,我可以检查是否有突变。我有一个versionNumber列,每次更新表时都会增加1。我可以使用此versionNumber来验证行是否已突变?

之类的东西

if (:new.versionNum != :old.versionNum) raise_application_error(20000, 'Mutated'); end if;

我的问题是我在哪里开始编写代码行FOR UPDATE?我做了一个小GUI来处理更改名字并将它们保存回数据库。这是在oracle上的那个表上还是在JDBC客户端的一个触发器中完成的?

任何澄清都会很好!

由于

1 个答案:

答案 0 :(得分:2)

锁定有两种常用方法。

首先,你有悲观的锁定。在此方法中,您锁定行(SELECT ... FOR UPDATE),以防止其他人更改行。然后你做UPDATE。提交更改时,将释放锁定。在这种情况下,不需要具有版本号/时间戳列(至少不支持锁定),并且代码相对容易。

悲观锁定的缺点是,您需要在用户坐在可能编辑数据的页面上时保持锁定。如果您正在构建基于Web的应用程序,那么这在技术上确实很难,因为HTTP是无状态协议。最初呈现页面的请求通常会从连接池获得连接,执行SELECT,然后在页面完成后将连接返回到池。后续更新数据的请求通常发生在具有不同数据库会话的不同连接上,因此您无法在第一个会话中锁定行并在第二个会话中更新它。如果您想悲观地锁定该行,则需要在后端执行大量工作,以确保将一个数据库连接绑定到特定的中间层会话,直到用户完成编辑数据为止。这通常会对可伸缩性产生非常不利的影响并引入各种会话管理问题 - 例如,您如何知道我是否请求了页面,锁定了一行,然后关闭了我的浏览器而没有注销或进行更改?您要将记录锁定在数据库中多长时间?如果某个其他会话试图锁定该行会发生什么?如果第一个人出去吃午饭,你会让这个会话阻止等待锁多长时间?通常,人们不会在基于Web的应用程序中实现悲观锁定,因为管理会话和会话状态实在太不切实际。

第二个选项是乐观锁定。在此方法中,您将向行添加版本号/时间戳。在查询数据时选择此版本号/时间戳。然后,在稍后进行更新时,在WHERE子句中使用它,并检查实际修改的行数。如果您只修改了一行,则表示您在读取该行后没有更改该行。如果修改0行,则表示该行确实已更改,您可以处理错误。

因此,例如,您将选择数据以及版本号

SELECT address_line1, city, state, zip, version
  FROM addressTable
 WHERE address_id = `<<some key>>`

当您准备好进行更新时,您会执行以下操作:使用version中的UPDATE并在行更改时抛出错误

UPDATE addressTable
   SET address_line1 = `<<new address line 1>>`,
       city = `<<new city>>`,
       state = `<<new state>>`,
       zip = `<<new zip>>`,
       version = version + 1
 WHERE address_id = `<<some key>>`
   AND version = `<<version you read initially>>`

IF( SQL%ROWCOUNT = 0 )
THEN
  -- Darn.  The row must have changed since you read it.  Do something to
  -- alert the user.  Most likely, the application will need to re-query the
  -- data to see what the address has been changed to and then ask the user
  -- whether they want to re-apply the changes.
  RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;

然后,您的应用程序将对错误执行一些有用的操作。通常,这意味着要做一些事情,比如再次查询数据,向用户显示更改,并询问他们是否仍然想要应用他们的更改。例如,如果我读了一个地址并开始编辑它,去吃午餐,我的同事登录,读取相同的地址,进行一些编辑并保存,然后我返回并尝试保存我的更改,这通常是有道理的向我展示一些事情,告诉我我的同事已经将地址更改为新的内容 - 我是否要继续进行编辑,或者我是否要放弃它们。