`
fengan321
  • 浏览: 3268 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

Hibernate Gossip: 乐观锁定(Optimistic locking)

阅读更多
Hibernate Gossip: 乐观锁定(Optimistic locking)[size=xx-small][/size]

悲观锁定假定任何时刻存取数据时,都可能有另一个客户也正在存取同一笔数据,因而对数据采取了数据库层次的锁定状态,在锁定的时间内其它的客户不能对数据 进行存取,对于单机或小系统而言,这并不成问题,然而如果是在网络上的系统,同时间会有许多联机,如果每一次读取数据都造成锁定,其后继的存取就必须等 待,这将造成效能上的问题,造成后继使用者的长时间等待。

乐观锁定(Optimistic locking)则乐观的认为数据的存取很少发生同时存取的问题,因而不作数据库层次上的锁定,为了维护正确的数据,乐观锁定使用应用程序上的逻辑实现版本控制的解决。

在不实行悲观锁定策略的情况下,数据不一致的情况一但发生,有几个解决的方法,一种是先更新为主,一种是后更新的为主,比较复杂的就是检查发生变动的数据来实现,或是检查所有属性来实现乐观锁定。

Hibernate中透过版本号检查来实现后更新为主,这也是Hibernate所推荐的方式,在数据库中加入一个version字段记录,在读取数据时 连同版本号一同读取,并在更新数据时比对版本号与数据库中的版本号,如果等于数据库中的版本号则予以更新,并递增版本号,如果小于数据库中的版本号就丢出 例外。

实际来透过范例了解Hibernate的乐观锁定如何实现,首先在数据库中新增一个表格:

CREATE TABLE user (
    id INT(11) NOT NULL auto_increment PRIMARY KEY,
    version INT,
    name VARCHAR(100) NOT NULL default '',
    age INT
);

这个user表格中的version用来记录版本号,以供Hibernate实现乐观锁定,接着设计User类别,当中必须包括version属性:
User.java

package onlyfun.caterpillar;

public class User {
    private Integer id;
    private Integer version; // 增加版本屬性  
    private String name;
    private Integer age;
   
    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }
   
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

在映射文件的定义方面,则如下所示:
User.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="onlyfun.caterpillar.User"
           table="user"
           optimistic-lock="version">
          
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native"/>
        </id>

        <version name="version"
                 column="version"
                 type="java.lang.Integer"/>
                
        <property name="name" column="name" type="java.lang.String"/>

        <property name="age" column="age" type="java.lang.Integer"/>
       
    </class>

</hibernate-mapping>

注意<version>标签必须出现在<id>卷标之后,接着您可以试着在数据库中新增数据,例如:

User user = new User();
user.setName(  "caterpillar");
user.setAge(new Integer(30));
Session session = sessionFactory.openSession();
Transaction tx =    session.beginTransaction();
session.save(user);
tx.commit();
session.close();

您可以检视数据库中的数据,每一次对同一笔数据进行更新,version字段的内容都会自动更新,接着来作个实验,直接以范例说明:

// 有使用1者开启了一个session1
Session session1 = sessionFactory.openSession();
// 在这之后,马上有另一个使用者2开启了session2
Session session2 = sessionFactory.openSession();

Integer id = new Integer(1);

// 使用者1查询数据 
User userV1 = (User) session1.load(User.class, id);
// 使用者2查询同一笔数据
User userV2 = (User) session2.load(User.class, id);

// 此时两个版本号是相同的
System.out.println(  " v1 v2 "+ userV1.getVersion().intValue() + " "  + userV2.getVersion().intValue());

Transaction tx1 = session1.beginTransaction();
Transaction tx2 = session2.beginTransaction();

// 使用者1更新数据
userV1.setAge(new Integer(31));
tx1.commit();

// 此时由于数据更新,数据库中的版本号递增了
// 两笔数据版本号不一样了
System.out.println(  " v1 v2 "+ userV1.getVersion().intValue() + " " + userV2.getVersion().intValue());

// userV2 的 age 资料还是旧的
//   数据更新
userV2.setName(  "justin");
// 因版本号比数据库中的旧
// 送出更新数据会失败,丢出StableObjectStateException例外
tx2.commit();

session1.close();
session2.close();

运行以下的程序片段,会出现以下的结果:

Hibernate:
select user0_.id as id0_, user0_.version as version0_0_, user0_.name as
name0_0_, user0_.age as age0_0_ from user user0_ where user0_.id=?
Hibernate:
select user0_.id as id0_, user0_.version as version0_0_, user0_.name as
name0_0_, user0_.age as age0_0_ from user user0_ where user0_.id=?
v1 v2 0 0
Hibernate: update user set version=?, name=?, age=? where id=? and version=?
v1 v2 1 0
Hibernate: update user set version=?, name=?, age=? where id=? and version=?
16:11:43,187 ERROR AbstractFlushingEventListener:277 - Could not synchronize database state with session
org.hibernate.StaleObjectStateException:
Row was updated or deleted by another transaction (or unsaved-value
mapping was incorrect): [onlyfun.caterpillar.User#1]
    at org.hibernate.persister.entity.BasicEntityPersister.check(BasicEntityPersister.java:1441)

由于新的版本号是1,而userV2的版本号还是0,因此更新失败丢出StableObjectStateException,您可以捕捉这个例外作善后 处理,例如在处理中重新读取数据库中的数据,同时将目前的数据与数据库中的数据秀出来,让使用者有机会比对不一致的数据,以决定要变更的部份,或者您可以 设计程序自动读取新的数据,并比对真正要更新的数据,这一切可以在背景执行,而不用让您的使用者知道。

要注意的是,由于乐观锁定是使用系统中的程序来控制,而不是使用数据库中的锁定机制,因而如果有人特意自行更新版本讯息来越过检查,则锁定机制就会无效, 例如在上例中自行更改userV2的version属性,使之与数据库中的版本号相同的话就不会有错误,像这样版本号被更改,或是由于数据是由外部系统而 来,因而版本信息不受控制时,锁定机制将会有问题,设计时必须注意。
分享到:
评论

相关推荐

    Java经典问题算法大全

    2.Algorithm Gossip: 费式数列. 3. 巴斯卡三角形 4.Algorithm Gossip: 三色棋 5.Algorithm Gossip: 老鼠走迷官(一) 6.Algorithm Gossip: 老鼠走迷官(二) 7.Algorithm Gossip: 骑士走棋盘 8.Algorithm Gossip: 八...

    经典算法大全

    巴斯卡三角形4.Algorithm Gossip: 三色棋5.Algorithm Gossip: 老鼠走迷官(一6.Algorithm Gossip: 老鼠走迷官(二7.Algorithm Gossip: 骑士走棋盘8.Algorithm Gossip: 八皇后9.Algorithm Gossip: 八枚银币10....

    经典算法大全.pdf

    巴斯卡三角形 6 4.Algorithm Gossip: 三色棋 7 5.Algorithm Gossip: 老鼠走迷官(一) 9 6.Algorithm Gossip: 老鼠走迷官(二) 11 7.Algorithm Gossip: 骑士走棋盘 13 8.Algorithm Gossip: 八皇后 ...

    开源框架:Hibernate Gossip v1.04

    开源框架:Hibernate Gossip v1.04

    Algorithm.rar_Algorithm Gossip_gossip_gossip algorithm_gossip算法

    2.Algorithm Gossip: 费式数列 3. 巴斯卡三角形 4.Algorithm Gossip: 三色棋 5.Algorithm Gossip: 老鼠走迷官 6.Algorithm Gossip: 老鼠走迷官(二) 7.Algorithm Gossip: 骑士走棋盘 8.Algorithm Gossip: 八皇 9....

    ACM51个经典算法大全

    老鼠走迷宫(二)7.Algorithm Gossip: 骑士走棋盘8.Algorithm Gossip: 八皇后9.Algorithm Gossip: 八枚银币10.Algorithm Gossip: 生命游戏11.Algorithm Gossip: 字串核对12.Algorithm Gossip: 双色、三色河内塔13....

    C 语言经典算法大全

    2.Algorithm Gossip: 费式数列......................... 5 3. 巴斯卡三角形........................................ 6 4.Algorithm Gossip: 三色棋.................. 7 5.Algorithm Gossip: 老鼠走迷官(一)......

    R-gossip:分布式负载均衡效率优化算法.pdf

    #资源达人分享计划#

    hibernate学习笔记

    Hibernate 学习笔记 Hibernate 学习笔记 1 第一个hibernate项目(hibernate_...Hibernate Gossip: 二级快取(Second-level) 48 hibernate查询缓存 50 hibernate抓取策略 53 Hibernate最佳实践(Best Practices) 55

    camel-gossip:骆驼八卦

    草稿用法: from("gossip://&lt;bound&gt;:&lt;port&gt;/?peers=&lt;listOfPeers&gt;&routeIds=&lt;listOfRouteIdsToControl&gt;").to("controlbus:route");listOfRouteIdsToControl在此节点被提升/降级时启动/停止。 当您在需要故障转移...

    gossip:Gossip协议的Go实现

    Gossip协议的Go实现。 概述 该软件包提供了最终一致的内存中数据存储的实现。 数据存储值使用推挽式八卦协议进行交换。 // Create a gossiper g := NewGossiper("&lt;ip&gt;:&lt;port&gt;", "&lt;unique&gt;", "&lt;peer&gt;") // Add ...

    R-gossip:分布式负载均衡效率优化算法

    针对在分布式一致性系统中常用的gossip算法负载均衡效率较低的问题,本文在概率gossip算法(probabilistic gossip algorithm)的基础上,设计了一种寄存器gossip算法(register gossip algorithm,下文简称R-gossip...

    Java算法经典案列

    2.Algorithm Gossip: 费式数列 3. 巴斯卡三角形 4.Algorithm Gossip: 三色棋 6.Algorithm Gossip: 老鼠走迷官(二) 7.Algorithm Gossip: 骑士走棋盘 9.Algorithm Gossip: 八枚银币

    99乘法表java源码-gossip:一个javalisp解析器

    gossip - yet another lisp interpreter gossip是一个lisp解释器, 语法借鉴了scheme以及common lisp, 此项目的主要目的是学习。 安装 下载源码 打包: mvn package 运行方式: java -jar your_gossip_home/gossip-1.0-...

    C语言经典算法

    非常完美的C语言经典算法 Algorithm Gossip: 2 2N+1 魔方阵 Algorithm Gossip: 4N 魔方阵 Algorithm Gossip: 奇数魔方阵 Algorithm Gossip: 上三角 下三角 对称矩阵

    nodejs_gossip:nodejs八卦协议实现

    nodejs_八卦 nodejs八卦协议实现 nodejs 八卦.js 连接到 localhost:8080 在 chrome 中查看网络状态 控制台命令: 重启重置对等体颜色 css_color 建立网络的节点 断网示例 重建网络

    cc++经典算法大全.pdf

    2.AlgorithmGossip:费式数列........................................................................................................5 3.巴斯卡三角形.........................................................

Global site tag (gtag.js) - Google Analytics