Hibernate 中的悲观锁和乐观锁

来源:互联网 发布:自动供料机的plc编程 编辑:程序博客网 时间:2024/05/01 18:37
        悲观锁和乐观锁用于处理数据的并发访问。Hibernate中有一种特殊的属性,即版本(Version)属性。版本属性不参与业务逻辑,只用来保证不会有两个线程同时对数据进行写操作。版本属性是乐观锁的一种实现方式。乐观锁是相对于悲观锁而言的,悲观锁与乐观锁都是保证数据准确性的机制。

什么是悲观锁

        悲观锁假定其他用户企图访问或者改变正在访问、更改的对象的概率是很高的,因此在悲观锁的环境中,在开始改变此对象之前就将该对象锁住,并且直到你提交了所作的更改之后才释放此锁。
        为保证数据的准确性,程序必须保证在一个线程修改数据的时候,该数据没有被其他线程修改。在传统的数据库编程中,程序修改数据时先锁定该数据行,使其他程序无法修改该行数据,修改完毕后释放数据锁,以此保证数据准确性。由于该机制需要锁定数据行,被锁定的数据只能被一个线程使用,因此被称为悲观锁。

悲观锁的使用

        Hibernate的悲观锁是使用SQL语句或者HQL语句实现的,下面是一个典型的依赖数据库的悲观锁调用,代码如下。    
     select * from users where name = 'Jack' for update
        这条SQL语句锁定了users表中所有符合检索条件(name="Jack")的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。Hibernate的悲观锁也是基于数据库的锁机制实现的。
        下面的代码实现了对查询记录的加锁。   
    String hql = "from Users where name = "Jack";    Query query = session.createQuery(hql);    query.setLockMode("users",LockMode.UPGRADE);  //对users表进行加锁    List list = query.list();                     //执行查询,获取数据     
        query.setLockMode对查询语句中,特定数据库表中的记录进行加锁(这里是users表),也就是对返回的所有users记录进行加锁。

Hibernate的加锁模式有:
        LockMode.NONE :无锁机制。
        LockMode.WRITE :Hibernate在 Insert和 Update记录的时候会自动获取。
        LockMode.READ :Hibernate在读取记录的时候会自动获取。

        以上这三种锁机制一般由 Hibernate内部使用,如Hibernate为了保证 Update过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE锁。
        LockMode.UPGRADE :利用数据库的 for update 子句加锁。
        LockMode. UPGRADE_NOWAIT : Oracle的特定实现,利用 Oracle的 for update nowait子句实现加锁。


什么是乐观锁

        与悲观锁相反,乐观锁使用完全不同的方式。乐观锁通过Version列保存当前数据版本,如果程序修改了数据,将将版本列加1.反过来,如果版本列有了变化,说明该数据被修改过了。程序保存数据时会检查数据的Version列。如果Version列已经发生了变化,程序会重新读取、修改并保存数据。由于该机制不需要锁定数据行,允许多线程同时访问同一条数据,因此被称为乐观锁。乐观锁的效率要高于悲观锁,因此现代编程更倾向于乐观锁。

        乐观锁则认为其他用户企图改变正在更改的对象的概率是很小的,因此乐观锁直到准备提交所作的更改时才将对象锁住,读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能。


乐观锁的配置

        Hibernate支持乐观锁,保存数据时Hibernate会自动完成检查Version列、修改数据、更新Version列等工作。Hibernate隐藏了所有的Version操作细节,只需要指定实体类的Version列即可。实体类中可用@Version配置版本属性,版本列一般为数字类型属性,代码如下。

    @Version    private int version;

        XML中使用<version />配置乐观锁,使用name属性版本列,注意,<version />版本列要配置在<id />主键后面、<property />普通属性前面,代码如下。 

    <version name="version"></version>

        XML配置版本属性要比@配置灵活,版本属性即可以为int、long等数据类型,也可以为Timestamp时间戳等类型,配置时用type配置类型,代码如下。   

    <version type="timestamp" column="version"></version>

        或者直接用<timestamp />配置日期版本,与上面的配置是等价的,代码如下。    

    <timestamp column="version" />

2 0
原创粉丝点击