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

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

Hibernate的并发控制_第1张图片

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

Hibernate的并发控制_第2张图片

②乐观锁

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

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

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

用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字段用于版本控制:

Hibernate的并发控制_第3张图片

在映射文件中:






    
    
        
            
        
        
        
        
        
        
    

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

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

你可能感兴趣的:(Hibernate)