Hibernate学习---第十二节:Hibernate之锁机制&乐观锁实现

1、悲观锁

它指的是对数据被外界修改保持保守态度,因些,在整个数据处理过程中,将数据牌锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层的锁机制才能保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

一个典型的悲观锁调用示例:

select * from account where name = "12345" for update

通过for update子句,这条SQL锁定了account表中所有符合检索条件的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。

2、乐观锁

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制,以操作最大程度的独占性。但随着而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。

乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于库表的版本解决方案中,一般是通过为数据库表增加version字段来实现。

读取出数据时,将此版本号一同读出,之生更新时,对此版本号加1.此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

例如,两个人同时在同一个帐号取钱,账号有100,A取50,B取20,A先提交,B的余额即为80,这时就不同步了,A提交后版本已经变了2了,而B看到的还是1的版本,此时B的提交必须被驳回。

需要注意的是,乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性。如有些例子,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户余额更新操作不受我们系统控制,因此可能会造成非法数据被更新到数据库中。

在系统设计阶段,我们应该充分考虑到某些情况出现的可能性,并进行相应调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。

Hibernate 在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数据库的更新操作,利用Hibernate提供的透明化乐观锁实现,将大大提升我们的生产力。

(1)、实体类

package learn.hibernate.bean;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * 持久化类设计
 * 注意:
 *         持久化类通常建议要有一个持久化标识符(ID)
 *         持久化标识符通常建议使用封装类(例如:Integer  因为基本类型存在默认值)
 *         持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的)
 *         属性通常建议提供  getter/setter 方法
 *         持久化类不能使用 final 修饰
 *         持久化类中如果使用了集合类型数据,只能使用集合所对应的接口类型来声明(List/Map/Set)
 *              如下:ArrayList list = new ArrayList();  不行
 *                 List list = new ArrayList(); 可行
 */
public class Person {

    private Integer id;
    private String name;
    private int age;
    private int passwork;
    private Date birthday;
    private Integer version;
    
    public Person() {
        
    }
    
    public Person(String name, int age, int passwork, Date birthday) {
        super();
        this.name = name;
        this.age = age;
        this.passwork = passwork;
        this.birthday = birthday;
    }
    
    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", age=" + age
                + ", passwork=" + passwork + ", birthday=" + birthday + "]";
    }
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getPasswork() {
        return passwork;
    }
    public void setPasswork(int passwork) {
        this.passwork = passwork;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }
}

(2)、持久化映射文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="learn.hibernate.bean">
    <!-- 
        optimistic-lock="version" 指定持久化类的乐观锁策略
     -->
    <class name="Person" table="t_person" optimistic-lock="version">
        <id name="id" column="person_id">
            <generator class="native"/>
        </id>
        <!-- 配置 锁字段和对应的属性关联,以及字段类型 -->
        <version name="version" column="t_version" type="integer"/>
        <property name="name" column="t_name"/>
        <property name="age"/>    
        <property name="passwork"/>
        <property name="birthday"/>
    </class>
</hibernate-mapping>

(3)、测试类

/**
 * hibernate 在获取数据的时候返回一个锁状态
 * 在提交数据的时候会自动的将锁状态进行改变
 */
@Test
public void testUpdate(){
    Person p1 = (Person)s1.get(Person.class, 1);
    Person p2 = (Person)s2.get(Person.class, 1);
    
    System.out.println("----------1---start-----------");
    tx = s1.beginTransaction();
    p1.setName("p1");
    s1.update(p1);
    tx.commit();
    System.out.println("----------1---end-----------");
    
    System.out.println("----------2---start-----------");
    tx = s2.beginTransaction();
    p2.setName("p2");
    s2.update(p2);
    tx.commit();
    System.out.println("----------2---end-----------");
}

可以查看:http://blog.csdn.net/shen516/article/details/8599068

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。