Hibernate(24)Hibernate如何实现乐观锁?

Hibernate实现乐观锁

乐观锁(Optimistic Locking)是一种并发控制机制,它允许多个事务并发地读取和修改相同的数据,但在提交时会检查数据是否被其他事务修改过。如果数据被其他事务修改过,当前事务会回滚并重新尝试。乐观锁通常通过版本号(version number)或时间戳(timestamp)来实现。

在Hibernate中,乐观锁可以通过在实体类上添加@Version注解来实现。当一个事务尝试更新数据时,Hibernate会检查版本号或时间戳是否与数据库中的值匹配。如果不匹配,则抛出OptimisticLockException

实现步骤

  1. 创建实体类 并在需要使用乐观锁的字段上添加@Version注解。
  2. 配置Hibernate
  3. 使用Hibernate进行CRUD操作,演示乐观锁的工作原理。

示例代码

配置文件 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.Person"/>
    </session-factory>
</hibernate-configuration>
实体类 Person

在实体类中使用@Version注解。

java 复制代码
package com.example.domain;

import javax.persistence.*;

@Entity
@Table(name = "person")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private int age;

    @Version
    @Column(name = "version")
    private int version;

    public Person() {}

    public Person(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;
    }
}

使用Hibernate进行CRUD操作

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;
    }
}
乐观锁使用示例
java 复制代码
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.exception.OptimisticLockException;

public class HibernateOptimisticLockExample {
    public static void main(String[] args) {
        // 获取SessionFactory
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        // 创建示例数据
        createPerson(sessionFactory);

        // 模拟两个并发事务进行更新操作
        simulateConcurrentUpdates(sessionFactory);

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

    private static void createPerson(SessionFactory sessionFactory) {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            Person person = new Person("John Doe", 30);
            session.save(person);
            transaction.commit();
            System.out.println("Inserted Person: " + person.getName());
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    private static void simulateConcurrentUpdates(SessionFactory sessionFactory) {
        // 第一个事务
        Thread thread1 = new Thread(() -> updatePerson(sessionFactory, 1L, "John Doe 1", 31));
        // 第二个事务
        Thread thread2 = new Thread(() -> updatePerson(sessionFactory, 1L, "John Doe 2", 32));

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void updatePerson(SessionFactory sessionFactory, Long personId, String newName, int newAge) {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            // 获取Person实体
            Person person = session.get(Person.class, personId);
            if (person != null) {
                // 更新Person实体字段
                person.setName(newName);
                person.setAge(newAge);
                // 提交事务前会检查版本号
                session.update(person);
                transaction.commit();
                System.out.println("Updated Person: " + person.getName() + ", Age: " + person.getAge());
            } else {
                System.out.println("No Person found with ID: " + personId);
            }
        } catch (OptimisticLockException e) {
            if (transaction != null) {
                transaction.rollback();
            }
            System.err.println("Optimistic lock exception encountered for Person ID: " + personId);
            e.printStackTrace();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
}

详细解释

  1. 配置文件 hibernate.cfg.xml:定义数据库连接信息、Hibernate属性配置以及实体类映射配置。

    xml 复制代码
    <mapping class="com.example.domain.Person"/>
  2. 实体类 Person :使用@Version注解定义版本字段。

    • @Version:表示版本字段,用于乐观锁的实现。每次更新时,Hibernate会检查版本号是否匹配。
    java 复制代码
    @Version
    @Column(name = "version")
    private int version;
  3. HibernateUtil类:创建并管理SessionFactory。

    java 复制代码
    public class HibernateUtil {
        // 创建SessionFactory的代码
    }
  4. CRUD操作类:演示了如何使用Hibernate进行插入操作和模拟并发更新操作。

    java 复制代码
    public class HibernateOptimisticLockExample {
        // CRUD操作方法
    }
  5. 模拟并发更新:使用两个线程来模拟并发更新同一个实体,从而展示乐观锁的工作原理。

    java 复制代码
    private static void simulateConcurrentUpdates(SessionFactory sessionFactory) {
        // 第一个事务
        Thread thread1 = new Thread(() -> updatePerson(sessionFactory, 1L, "John Doe 1", 31));
        // 第二个事务
        Thread thread2 = new Thread(() -> updatePerson(sessionFactory, 1L, "John Doe 2", 32));
    
        thread1.start();
        thread2.start();
    
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

总结

通过在实体类中添加@Version注解,Hibernate可以实现乐观锁。当多个事务并发地修改同一实体时,乐观锁确保了只有版本号匹配的事务才能成功提交,从而避免数据不一致的问题。通过模拟并发更新操作,可以清楚地看到乐观锁的工作原理和效果。

相关推荐
言慢行善5 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星5 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟5 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z5 小时前
常见的限流算法和实现原理
java·开发语言
凭君语未可5 小时前
Java 中的实现类是什么
java·开发语言
He少年5 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
克里斯蒂亚诺更新5 小时前
myeclipse的pojie
java·ide·myeclipse
迷藏4946 小时前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏4946 小时前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链