Hibernate中乐观锁的实现示例

 更新时间:2026年01月11日 09:32:32   作者:辞暮尔尔-烟火年年  
Hibernate的乐观锁通过版本号机制实现并发控制,在数据更新时检查版本号是否一致,下面就来介绍一下乐观锁如何实现,感兴趣的可以了解一下

Hibernate的乐观锁(Optimistic Locking)是一种并发控制机制,用于防止在多个事务并发访问相同数据时出现数据冲突。乐观锁的基本思想是,每次读取数据时不进行实际的加锁操作,而是在提交更新时检查数据是否已经被其他事务修改。如果数据在此期间被其他事务修改,则当前事务会回滚并重新尝试。

乐观锁的实现

乐观锁通常通过版本号(version)字段实现。每次更新数据时,都会检查版本号是否一致,并将版本号加1。

示例代码

下面是一个完整的示例,展示如何在Hibernate中使用乐观锁。

配置文件hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 数据库连接配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/your_database</property>
        <property name="hibernate.connection.username">your_username</property>
        <property name="hibernate.connection.password">your_password</property>

        <!-- Hibernate 属性配置 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">update</property>

        <!-- 映射类配置 -->
        <mapping class="com.example.domain.Student"/>
    </session-factory>
</hibernate-configuration>

HibernateUtil 类

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            // 从配置文件创建SessionFactory
            sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
        } catch (Throwable ex) {
            // 记录启动失败的错误
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

实体类 Student

package com.example.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Version;

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private int age;

    @Version
    private int version;

    public Student() {}

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getters 和 setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getVersion() {
        return version;
    }

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

乐观锁示例代码

下面的示例展示了如何在并发环境中使用乐观锁。

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class HibernateOptimisticLockingExample {
    public static void main(String[] args) {
        // 获取SessionFactory
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        
        // 第一个会话
        Session session1 = sessionFactory.openSession();
        Transaction transaction1 = session1.beginTransaction();
        
        // 第二个会话
        Session session2 = sessionFactory.openSession();
        Transaction transaction2 = session2.beginTransaction();

        try {
            // 在第一个会话中获取对象
            Student student1 = session1.get(Student.class, 1L);
            System.out.println("Session1 - Student: " + student1.getName() + ", Age: " + student1.getAge() + ", Version: " + student1.getVersion());

            // 在第二个会话中获取相同的对象
            Student student2 = session2.get(Student.class, 1L);
            System.out.println("Session2 - Student: " + student2.getName() + ", Age: " + student2.getAge() + ", Version: " + student2.getVersion());

            // 修改并更新对象
            student1.setAge(21);
            session1.update(student1);
            transaction1.commit();
            System.out.println("Session1 - Updated Student: " + student1.getName() + ", Age: " + student1.getAge() + ", Version: " + student1.getVersion());

            // 尝试在第二个会话中提交修改
            student2.setAge(22);
            session2.update(student2);
            transaction2.commit(); // 这里会抛出异常,因为版本号不一致

        } catch (Exception e) {
            if (transaction2 != null) {
                transaction2.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session1 != null) {
                session1.close();
            }
            if (session2 != null) {
                session2.close();
            }
        }

        // 关闭SessionFactory
        sessionFactory.close();
    }
}

详细解释

  1. 配置乐观锁:在实体类中添加一个@Version注解的字段,通常为整数类型。

    @Version
    private int version;
    
  2. 示例场景

    • 在第一个会话中获取同一个Student对象,修改其属性并提交更新。
    • 在第二个会话中获取同一个Student对象,也修改其属性并试图提交更新。
    • 由于版本号不一致,第二个会话在提交更新时会抛出异常(org.hibernate.StaleObjectStateException)。
  3. 事务管理:在事务中进行数据操作,并在操作完成后提交事务。如果操作失败,则回滚事务以确保数据一致性。

总结

乐观锁是一种有效的并发控制机制,通过版本号字段可以防止多个事务并发修改相同数据时出现数据冲突。在Hibernate中,通过@Version注解可以非常方便地实现乐观锁。理解并正确应用乐观锁,可以有效地提高应用的并发处理能力和数据一致性。

到此这篇关于Hibernate中乐观锁的实现示例的文章就介绍到这了,更多相关Hibernate 乐观锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 部署springboot项目到云服务器的两种方式(jar+war)

    部署springboot项目到云服务器的两种方式(jar+war)

    本文主要介绍了部署springboot项目到云服务器的两种方式,主要介绍了jar和war两种方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java中的System类、BigInteger类和BigDecimal类详解

    Java中的System类、BigInteger类和BigDecimal类详解

    这篇文章主要介绍了Java中的System类、BigInteger类和BigDecimal类详解,arraycopy()方法,复制数组元素,比较适合底层调用,一般使用Arrays.copyOf()完成复制数组,需要的朋友可以参考下
    2023-09-09
  • 解决Springboot获取不到nacos配置中心的配置问题

    解决Springboot获取不到nacos配置中心的配置问题

    由于项目使用的nacos老版本,存在风险bug, 需要将nacos升级至2.2.1及以上版本,版本升级完毕之后 启动项目发现项目开始报错,所以本文记录一下Springboot获取不到nacos配置中心的配置问题,文中有详细的解决方法,需要的朋友可以参考下
    2023-09-09
  • java面试题之数组中的逆序对

    java面试题之数组中的逆序对

    这篇文章主要为大家详细介绍了java面试题之数组中的逆序对,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • Java代理模式的示例详解

    Java代理模式的示例详解

    代理模式(Proxy Parttern)为一个对象提供一个替身,来控制这个对象的访问,即通过代理对象来访问目标对象。本文将通过示例详细讲解一下这个模式,需要的可以参考一下
    2022-08-08
  • Kafka的生产者和消费者机制使用方式

    Kafka的生产者和消费者机制使用方式

    本文介绍了Kafka的HighLevelAPI和LowLevelAPI,并详细讲解了Kafka生产者和消费者的基本流程、工作机制、分区路由机制、消息缓存机制、发送应答机制、消息幂等性以及消息事务机制
    2025-11-11
  • Springboot  jar包 idea 远程调试的操作过程

    Springboot  jar包 idea 远程调试的操作过程

    文章介绍了如何在IntelliJ IDEA中远程调试Spring Boot项目的Jar包,本文通过图文并茂的形式给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • JAVA冒泡排序和二分查找的实现

    JAVA冒泡排序和二分查找的实现

    本文详细介绍了JAVA冒泡排序和二分查找的实现,虽然这两种算法比较简单,但是确实我们必须需要掌握的。下面来看看。
    2016-07-07
  • SpringBoot集成Mybatis并测试

    SpringBoot集成Mybatis并测试

    这篇文章主要介绍了SpringBoot集成Mybatis并测试,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • Java中的BigDecimal使用问题小结

    Java中的BigDecimal使用问题小结

    BigDecimal 是 Java 中用于进行精确十进制计算的重要类, 它适用于金融、科学等需要高精度计算的场景,这篇文章让我来详细讲解 Java 中的 BigDecimal 类,包括它的用途、适用场景、以及潜在问题,感兴趣的朋友一起看看吧
    2025-04-04

最新评论