Hibernate的并发控制

①悲观锁

悲观锁是数据库的机制, 并不是Hibernate框架提供的, 例如: select * from item for update, 此时数据库就被上锁了, A在查询时, B是不能查询的, 是被阻塞在外面的

新建一个Item类:

package com.rl.hiber.model;

public class Item {

    private Integer itemId;
    
    private String itemName;
    
    private Integer stock;

    public Integer getItemId() {
        return itemId;
    }

    public void setItemId(Integer itemId) {
        this.itemId = itemId;
    }

    public String getItemName() {
        return itemName;
    }

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

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

映射文件就不贴上来了

测试代码:

@Test
    public void updateStock(){
        
        Session session = HibernateUtil.getSessoion();
        Transaction tx = session.beginTransaction();
        try {
            //设置悲观锁, 当有一个线程在查询的时候, 此时其他的线程都被阻塞在外面, 只有当其提交之后, 悲观锁才会释放
            Item item = (Item) session.load(Item.class, 1, LockOptions.UPGRADE);
            item.setStock(item.getStock()-2);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtil.closeResource(session);
        }
    }

打个断点, 很明显可以看出查询语句是带悲观锁的(for update)

Hibernate: select item0_.item_id as item_id1_0_0_, item0_.item_name as item_nam2_0_0_, item0_.stock as stock3_0_0_ from t_item item0_ where item0_.item_id=? for update

此时如果有第二个线程进来则会被阻塞在外面:

当第一个线程提交后, 第二个线程马上执行, 此时item的库存由100变为96:

②乐观锁

悲观锁是有很大缺点的, 因为很多请求都会被阻塞在外面, 所以对性能的影响极大, 一般都不会采用悲观锁的方式

乐观锁就很好的解决了这个问题

乐观锁的机制是在表中追加一个用于版本控制的字段, 该字段会伴随着每次修改而改变, 假如同时有两个线程修改数据库, 则第二个修改的那个线程一定会发现数据库中的版本发生了改变, 此时就会抛异常, 程序就可以捕捉到该异常, 从而使其再次发出请求, 而用户是不会感知到的.

用sql实现:

update t_item t set t.stock = 100 - 2, t.version = t.version + 1 where t.item_id = 1001 and t.version = 1

其实Hibernate框架会帮我们实现这个过程, 我们只需要在Item类中追加一个version字段用于版本控制:

在映射文件中:

<?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="com.rl.hiber.model">

    <class name="Item" table="t_item">
    
        <id name="itemId" column="item_id">
            <generator class="native"></generator>
        </id>
        
        <!-- 乐观锁的版本字段映射
         -->
        <version name="version"></version>
        <property name="itemName" column="item_name"></property>
        <property name="stock"></property>
    </class>
</hibernate-mapping>

注意: 此时version标签一定要在property标签之前

现在执行悲观锁的那个流程的话, 可以发现, 当线程1还没提交之前, 线程2可以直接减库存, 但是线程1就无法提交了从而抛异常, 在项目中可以设置程序捕捉到该异常, 从而让其再次发送请求即可.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值