zoukankan      html  css  js  c++  java
  • 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属性,使之与资料库中的版本号相同的话就不会有错误,像这样版本号被更改,或是由于资料是由外部系统而来,因而版本资讯不受控制时,锁定机制将会有问题,设计时必须注意。

  • 相关阅读:
    wince嵌入式应用程序开发环境搭建
    用户 'NT AUTHORITY\NETWORK SERVICE' 登录失败
    git# 建立个人级服务器仓库 git init bare
    Bind和Eval的区别详解
    控件包含代码块(即 <% ... %>),因此无法修改控件集合 (转自http://blog.csdn.net/wangchao1982/archive/2007/11/19/1892472.aspx)
    Sys.ArgumentOutOfRangeException: Value must be an integer 错误的原因
    判断Cookies是否处于开启状态
    多个解决方案引用同一工程文件时冲突的解决方法
    javascript无提示的关闭页面
    Server.MapPath()
  • 原文地址:https://www.cnblogs.com/crazylqy/p/4080711.html
Copyright © 2011-2022 走看看