025 hibernate悲观锁、乐观锁

Hibernate谈到悲观锁、乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差

         并发性:当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了。称为并发性不好

    数据库隔离级别:见前面章级

025-1悲观锁:

悲观锁:具有排他性(我锁住当前数据后,别人看到不此数据)

悲观锁一般由数据机制来做到的。

悲观锁的实现

通常依赖于数据库机制,在整修过程中将数据锁定,其它任何用户都不能读取或修改(如:必需我修改完之后,别人才可以修改)

悲观锁的适用场景:

悲观锁一般适合短事务比较多(如某一数据取出后加1,立即释放)

长事务占有时间(如果占有1个小时,那么这个1小时别人就不可以使用这些数据),不常用。

实例:

实体类:

public class Inventory {

    private int itemNo;
    private String itemName;   
    private int quantity;

    public int getItemNo() {
        return itemNo;
    }

    public void setItemNo(int itemNo) {
        this.itemNo = itemNo;
    }

    public String getItemName() {
        return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }  

}

 

映射文件:

<hibernate-mapping>
    <class name="com.wjt276.hibernate.Inventory" table="t_inventory">
        <id name="itemNo">
            <generator class="native"/>
        </id>
        <property name="itemName"/>
        <property name="quantity"/>
    </class>

</hibernate-mapping>

 

悲观锁的使用

如果需要使用悲观锁,肯定在加载数据时就要锁住,通常采用数据库的for update语句。

Hibernate使用Load进行悲观锁加载。

 

Session.load(Class arg0, Serializable arg1, LockMode arg2) throws HibernateException

LockMode:悲观锁模式(一般使用LockMode.UPGRADE)

session = HibernateUtils.getSession();
            tx = session.beginTransaction();
            Inventory inv = (Inventory)session.load(Inventory.class, 1, LockMode.UPGRADE);
            System.out.println(inv.getItemName());
            inv.setQuantity(inv.getQuantity()-200);        
            session.update(inv);
            tx.commit();

 

执行输出SQL语句:

Hibernate: select inventory0_.itemNo as itemNo0_0_, inventory0_.itemName as itemName0_0_, inventory0_.quantity as quantity0_0_ from t_inventory inventory0_ where inventory0_.itemNo=? for update //在select语句中加入for update进行使用悲观锁。

脑白金

Hibernate: update t_inventory set itemName=?, quantity=? where itemNo=?

注:只有用户释放锁后,别的用户才可以读取

注:如果使用悲观锁,那么lazy(悚加载无效)

Select…For Update语句的语法与select语句相同,只是在select语句的后面加FOR UPDATE [NOWAIT]子句。

该语句用来锁定特定的行(如果有where子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit语句或rollback语句结束为止。 

 

 

 

025-2乐观锁:

     乐观锁:不是锁,是一种冲突检测机制。

     乐观锁的并发性较好,因为我改的时候,别人随边修改。

     乐观锁的实现方式:常用的是版本的方式(每个数据表中有一个版本字段version,某一个用户更新数据后,版本号+1,另一个用户修改后再+1,当用户更新发现数据库当前版本号与读取数据时版本号不一致(等于小于数据库当前版本号),则更新不了。

         Hibernate使用乐观锁需要在映射文件中配置项才可生效。

实体类:

public class Inventory {

    private int itemNo;
    private String itemName;   
    private int quantity;  
    private int version;//Hibernate用户实现版本方式乐观锁,但需要在映射文件中配置

    public int getItemNo() {
        return itemNo;
    }

    public void setItemNo(int itemNo) {
       this.itemNo = itemNo;
    }

    public String getItemName() {
       return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public int getVersion() {
        return version;
    }

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

}

 

 

映射文件

 

<hibernate-mapping>

<!-- 映射实体类时,需要加入一个开启乐观锁的属性
optimistic-lock="version" 共有好几种方式:
    - none  - version   - dirty - all
    同时需要在主键映射后面映射版本号字段
    -->
<class name="com.wjt276.hibernate.Inventory" table="t_inventory" optimistic-lock="version">
        <id name="itemNo">
            <generator class="native"/>
        </id>

        <version name="version"/><!—必需配置在主键映射后面 -->
        <property name="itemName"/>
        <property name="quantity"/>
    </class>

</hibernate-mapping>

 

 

 

导出输出SQL语句:

create table t_inventory (itemNo integer not null auto_increment, version integer not null, itemName varchar(255), quantity integer, primary key (itemNo))

 

 

注:添加的版本字段version,还是我们来维护的,是由hibernate来维护的。

乐观锁在存储数据时不用关心。

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

posted @ 2014-11-07 10:52  crazyYong  阅读(310)  评论(0编辑  收藏  举报