科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Oracle数据库数据锁定机制解析(2)

Oracle数据库数据锁定机制解析(2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

为了得到最大的性能,一般数据库都有并发机制,不过带来的问题就是数据访问的冲突。为了解决这个问题,大多数数据库用的方法就是数据的锁定。

作者:gmcyt 来源:赛迪网技术社区 2007年9月5日

关键字: 机制 数据库 ORACLE

  • 评论
  • 分享微博
  • 分享邮件

与悲观锁相对的,我们有了乐观锁。乐观锁一开始也说了,就是一开始假设不会造成数据冲突,在最后提交的时候再进行数据冲突检测。在乐观锁中,我们有5种常用的做法来实现。

第一种就是在数据取得的时候把整个数据都copy到应用中,在进行提交的时候比对当前数据库中的数据和开始的时候更新前取得的数据。当发现两个数据一模一样以后,就表示没有冲突可以提交,否则则是并发冲突,需要去用业务逻辑进行解决。

第二种乐观锁的做法就是采用版本戳,这个在Hibernate中得到了使用。采用版本戳的话,首先需要在你有乐观锁的数据库table上建立一个新的column,比如为number型,当你数据每更新一次的时候,版本数就会往上增加1。比如同样有2个session同样对某条数据进行操作。两者都取到当前的数据的版本号为1,当第一个session进行数据更新后,在提交的时候查看到当前数据的版本还为1,和自己一开始取到的版本相同。就正式提交,然后把版本号增加1,这个时候当前数据的版本为2。当第二个session也更新了数据提交的时候,发现数据库中版本为2,和一开始这个session取到的版本号不一致,就知道别人更新过此条数据,这个时候再进行业务处理,比如整个Transaction都Rollback等等操作。在用版本戳的时候,可以在应用程序侧使用版本戳的验证,也可以在数据库侧采用Trigger(触发器)来进行验证。不过数据库的Trigger的性能开销还是比较的大,所以能在应用侧进行验证的话还是推荐不用Trigger。

第三种做法和第二种做法有点类似,就是也新增一个Table的Column,不过这次这个column是采用timestamp型,存储数据最后更新的时间。在Oracle9i以后可以采用新的数据类型,也就是timestamp with time zone类型来做时间戳。这种Timestamp的数据精度在Oracle的时间类型中是最高的,精确到微秒(还没与到纳秒的级别),一般来说,加上数据库处理时间和人的思考动作时间,微秒级别是非常非常够了,其实只要精确到毫秒甚至秒都应该没有什么问题。和刚才的版本戳类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。如果不想把代码写在程序中或者由于别的原因无法把代码写在现有的程序中,也可以把这个时间戳乐观锁逻辑写在Trigger或者存储过程中。

第四种做法就是采用散列算法。这种做法和第一种做法有点类似,就是把当前数据内容进行传递,最后在提交的时候进行比较。但是区别还是比较大的,第一种做法把整个更新前的数据都copy了下来进行传递,而这种做法只是把数据做了一个散列码,所以传递的数据要小的多,网络负荷也会因此小很多。这种采用散列算法的做法如果在Oracle侧生成散列的话,有三种方法可以生成。第一种就是利用Oracle8i 8.1.5以后的OWA_OPT_LOCK.CHECKSUM函数来进行数据的散列生成比如下面的例子。

select owa_opt_lock.checksum (to_char(sysdate,'YYYYMMDDHHMISS') ) from dual

在这里我用这个OWA_OPT_LOCK.CHECKSUM函数对当前的系统时间进行了散列,用这个方法生成的出土的可能性是65536,因为生成的散列算法是一个16位置的值,所以值范围也就是65536个值而已。

第二种散列算法采用Oracle8i 8.1.7以后提供的DBMS_OBFUSCATION_TOOLKIT.MD5方法,不过这个方法不能直接在SQL语句里面使用,需要在存储过程中调用。所以可以先写一个共通的存储过程的Function,然后利用这个function去进行加密。

第三种散列方法就是用Oracle 10g Release1种提供的DBMS_CRYPTO.HASH方法。这个方法可以计算一个SHA-1或者是MD5摘要,所以如果实际情况下使用Oracle 10g的数据库,建议采用这个方法。不过和第二种类似,这个方法也是需要采用存储过程才能够编写,不能直接应用在SQL语句中的。

最后一种做法就是采用Oracle 10g所带有的ORA_ROWSCN函数来进行乐观锁。ORA_ROWSCN是根据系统最后更新时间来进行计算。这个ORA_ROWSCN在默认情况下是采用数据块为单位的,也就是一个数据库块(block)上共享一个ORA_ROWSCN,当数据更新的时候,这个block快的ORA_ROWSCN就会自动更新。所以在默认情况下的话,有可能出现假冲突的情况。比如A,B,C,D四条数据都在一个block上,这个时候A数据更新了,ORA_ROWSCN也会更新,这个时候因为ABCD四条数据存储在一个block上,所以BCD的ORA_ROWSCN也更新过了,其实BCD三条数据并没有更新过,这个就造成了假更新的情况出现。见下面的SQL语句:select id, name, location, value, ora_rowscn from test。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章