gpt4 book ai didi

java - 使用 Hibernate 和 HSQLDB 在数据库级别锁定实体

转载 作者:行者123 更新时间:2023-11-30 09:22:50 24 4
gpt4 key购买 nike

我有一个系统,我需要在并发上下文中创建 SomeEntity 的新实例,使用另一个实体作为“监视器”,如下所示:

//Begin transaction 
Monitor monitor = (Monitor) session.load(Monitor.class, monitor.getId(), LockOptions.UPGRADE);
SomeEntity entity = createSomeEntity(monitor);
//Save entity and commit transaction

当我使用 Mysql 时,当我使用 LockOptions.UPGRADE 加载监视器时,这与锁定发生完美配合,但是当我使用 HSQLDB 时,上面的代码不起作用,并且所有线程都在数据库级别无锁地运行,导致在数据库中创建许多 SomeEntity 实例。

主要问题

我需要使用 Hibernate 和 HSQLDB 在数据库级别锁定实体。

例子

为了举例说明我的需要,我创建了一个简单的项目,其中我有一个名为 Person 的实体类,它具有两个属性(id 和名称)和一个主程序,它将以并发方式为单个实例更新名称属性(人#id = 1)。有3个线程竞争更新,所有线程都将通过以下指令在数据库级别同步:

Person person = (Person) session.load(Person.class, 1L, LockOptions.UPGRADE);

使用上面的代码一次只有一个线程将更新名称属性,所有其他线程将等待获取锁。

如果发生锁定,可以在 Hibernate 生成的 sql 代码中可视化,如下所示:

select
person0_.id as id1_0_0_,
person0_.name as name2_0_0_
from
Person person0_
where
person0_.id=? for update

或者可以在 Eclipse IDE 调试期间可视化,在调用 session.load(...) 的行处有一个断点(只有一个线程转到下一条指令,所有其他线程等待)。

所以,再次记住:这适用于 Mysql 但不适用于 HSQLDB

附件

package model;

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

@Entity
public class Person {

@Id
@GeneratedValue
private Long id;
private String name;

public Person() {}

public Person(String name) {
this();
this.name = name;
}

public String getName() {
return name;
}

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

}

package app;

import static java.util.concurrent.Executors.newFixedThreadPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import model.Person;

import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public class Main {

private static final SessionFactory sessionFactory = init();

public static void main(String[] args) {
populate();
changeNames("Christine", "Isabelle", "Katarina");
}

private static void changeNames(String... names) {
ExecutorService executor = newFixedThreadPool(3);

for (final String name : names) {
executor.execute(new Runnable() {

private Session session = sessionFactory.openSession();

public void run() {
Transaction transaction = null;

try {
transaction = session.beginTransaction();

// At next line I put a breakpoint to debug in Eclipse Juno SR2
Person person = (Person) session.load(Person.class, 1L, LockOptions.UPGRADE);
person.setName(name);
session.saveOrUpdate(person);

transaction.commit();

System.out.println("Name changed to " + name);
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}

e.printStackTrace();
}
finally {
session.close();
}
}
});
}

try {
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private static void populate() {
Session session = sessionFactory.openSession();

Transaction transaction = session.beginTransaction();
session.save(new Person("Old Name"));
transaction.commit();

session.close();
}

private static SessionFactory init() {
Configuration configuration = new Configuration().configure();

ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();

return configuration.buildSessionFactory(serviceRegistry);
}
}

<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory name="">
<mapping class="model.Person" />
</session-factory>
</hibernate-configuration>

hibernate.connection.driver_class = org.hsqldb.jdbcDriver
hibernate.dialect = org.hibernate.dialect.HSQLDialect
hibernate.connection.url = jdbc:hsqldb:mem:test;hsqldb.tx=locks;hsqldb.write_delay=false
hibernate.connection.username = sa
hibernate.connection.password =
hibernate.hbm2ddl.auto = update

#hibernate.connection.driver_class = com.mysql.jdbc.Driver
#hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
#hibernate.connection.url = jdbc:mysql://localhost/test
#hibernate.connection.username = root
#hibernate.connection.password =

hibernate.show_sql = true
hibernate.format_sql = true

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.12.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.9</version>
</dependency>
</dependencies>
</project>

最佳答案

似乎有一个 hibernate HSQLDialect 错误。它不会在生成的 SQL 中放入 for update:https://hibernate.atlassian.net/browse/HHH-7479

这个错误似乎在最新的测试版中得到了解决:4.3.0.Beta1

关于java - 使用 Hibernate 和 HSQLDB 在数据库级别锁定实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16306141/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com