Calvin's Tech Space

成于坚忍,毁于浮躁

   :: 首页 :: 联系 :: 聚合  :: 管理

 Oracle中乐观锁定的四种实现方式:

  • 更新前在应用中存储所要操作行的“前映像”,更新时使用存储的旧记录来判断当前值是否已经改变;
  • 使用一个特殊的列,这个列由一个数据库触发器或应用程序代码维护,可以告诉我们记录的 “版本”;
  • 使用一个校验和或散列值,这是使用原来的数据计算得出的;
  • 使用新增的 Oracle 10g 特性 ORA_ROWSCN 。

1.使用版本列
    附加一个LAST_MODIFIED列,类型可以为 timestamp with time zone default systemstamp(ora 9i以上),这个类型在Oracle中精度最高,精确到百万分之一秒。
不建议使用触发器,因为开销太大,而由DML来负责。

2.使用校验和的乐观锁定
    使用一个虚拟的版本列来判断数据是否改变。
    与使用版本列的做法一样,我们可以采用同样的方法使用这些散列值或校验和,只需把从数据库读出数据时得到的散列或校验和值与修改数据前得到的散列或校验和值进行比较。在我们读出数据之后, 但是在修改数据之前,如果有人在这段时间内修改了这一行的值,散列值或校验和值往往会大不相同。
    以下为Oracle提供的三种计算散列值得数据包:
OWA_OPT_LOCK.CHECKSUM :这个方法在 Oracle8i 8.1.5 及以上版本中提供。给定一个串,其中一个函数会返回一个 16 位的校验和。给定 ROWID 时,另一个函数会计算该行的 16 位校验和,而且同时将这一行锁定。出现冲突的可能性是 65 536 分之一( 65 536 个串中有一个冲突,这是假警报的最大几率)。
 DBMS_OBFUSCATION_TOOLKIT.MD5 :这个方法在 Oracle8i 8.1.7 及以上版本中提供。它会计算一个 128 位的消息摘要。冲突的可能性是 3.4028E+38 分之一(非常小)。
DBMS_CRYPTO.HASH :这个方法在 Oracle 10g Release 1 及以上版本中提供。它能计算一个SHA-1 (安全散列算法 1 , Secure Hash Algorithm 1 )或 MD4/MD5 消息摘要。建议你使用 SHA- 1算法。
    注意 很多编程语言中都提供了一些散列和校验和函数,所以还可以使用数据库之外的散列和校验和函数。
    要记住,计算散列或校验和是一个 CPU 密集型操作(相当占用 CPU ),其计算代价很昂贵。如果系统上 CPU 是稀有资源,在这种系统上就必须充分考虑到这一点。不过,如果从 “ 网络友好性 ” 角度看,这种方法会比较好,因为只需在网络上传输相当小的散列值,而不是行的完整的前映像和后映像(以便逐列地进行比较),所以消耗的资源会少得多。下面会使用一个新的 Oracle 10g 函数 ORA_ROWSCN ,它不仅很小(类似于散列),而且计算时不是 CPU 密集的(不会过多占用 CP U )。

3.使用ORA_ROWSCN
    ORA_ROWSCN 建立在内部 Oracle 系统时钟( SCN )基础上。在 Oracle 中,每次提交时, SCN 都会推进(其他情况也可能导致 SCN 推进,要注意, SCN 只会推进,绝对不会后退)。这个概念与前面在获取数据 时得到 ORA_ROWSCN 的方法是一样的,更新数据时要验证 SCN 未修改过。之所以我会强调这一点(而不是草草带过),原因是除非你创建表时支持在行级维ORA_ROWSCN ,否则 Oracle 会在块级维护。也就是说,默认情况下,一个块上的多行会共享相同的 ORA_ROWSCN 值。如果更新一个块上的某一行,而且 这个块上还有另外 50 行,那么这些行的 ORA_ROWSCN 也会推进。这往往会导致许多假警报,你认为某一行已经修改,但实际上它并没有改动。因此,需要注意这一点,并了解如何改变这种行为。
    要修改这个特性,只能重新建立表,并启用 ROWDEPENDENCIES

使用乐观锁定还是悲观锁定?

那么哪种方法最好呢?根据我的经验,悲观锁定在 Oracle 中工作得非常好(但是在其他数据库中可能不是这样),而且与乐观锁定相比,悲观锁定有很多优点。不过,它需要与数据库有一条有状态的连接,如客户 / 服务器连接,因为无法跨连接持有锁。正是因为这一点,在当前的许多情况下,悲观锁定不太现实。过去,客户 / 服务器应用可能只有数十个或数百个用户,对于这些应用,悲观锁定是我的不二选择。不过,如今对大多数应用来说,我都建议采用乐观并发控制。要在整个事务期间保持连接,这个代价太大了,一般无法承受。

在这些可用的方法中,我使用哪一种呢?我喜欢使用版本列方法,并增加一个时间戳列(而不只是一个 NUMBER )。从长远看,这样能为我提供一个额外的信息:这一行最后一次更新发生在什么时间?所以意义更大。而且与散列或校验和方法相比,计算的代价不那么昂贵,在处理 LONG LONG RAW CLOB BLO B和其他非常大的列时,散列或校验和方法可能会遇到一些问题,而版本列方法则没有这些问题。

如果必须向一个表增加乐观并发控制,而此时还在利用悲观锁定机制使用这个表(例如,客户 / 服务器应用都在访问这个表,而且还在通过 Web 访问),我则倾向于选择 ORA_ROWSCN 方法。这是因为,在现有的遗留应用中,可能不希望出现一个新列,或者即使我们另外增加一步把这个额外的列隐藏起来(使用散列等等方式),为了维护这个列,可能需要一个必要的触发器,而这个触发器的开销非常大,这是我们无法承受的。 ORA_ROWSCN技术没有干扰性,而且在这个方面是轻量级的(当然,这是指我们执行表的重建之后)。

散列 / 校验和方法在数据库独立性方面很不错,特别是如果我们在数据库之外计算散列或校验和,则更是如此。不过,如果在中间层而不是在数据库中执行计算,从 CPU 使用和网络传输方面来看,就会带来更大的资源使用开销。

posted on 2009-09-04 20:23 calvin 阅读(1318) 评论(0)  编辑  收藏 所属分类: Oracle

只有注册用户登录后才能发表评论。


网站导航: