Hibernate(16)什么是Hibernate的乐观锁?

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

乐观锁的实现

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

示例代码

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

配置文件 hibernate.cfg.xml

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 类

java 复制代码
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

java 复制代码
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;
    }
}

乐观锁示例代码

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

java 复制代码
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注解的字段,通常为整数类型。

    java 复制代码
    @Version
    private int version;
  2. 示例场景

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

总结

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

相关推荐
㳺三才人子3 小时前
初探 Flask
后端·python·flask·html
星栈独行3 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Java爱好狂.4 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易4 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
装不满的克莱因瓶4 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl5 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
excel5 小时前
为什么我推荐使用 Termius:现代 SSH 工具的完整体验
前端·后端
卷毛的技术笔记6 小时前
Java后端硬核实战:用Spring AI Alibaba+Redis给LLM装上“超强记忆中枢”
java·人工智能·redis·后端·spring·ai·系统架构
IT_陈寒7 小时前
Java的Optional差点让我掉坑里,这几个坑你别踩
前端·人工智能·后端
子兮曰7 小时前
Harness 驾驭工程深度教程:从 AGENTS.md 到全链路 AI 编码基础设施
前端·后端·ai编程