2

以下に示すように、別のエンティティを「モニター」として使用して、同時コンテキストで 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 を使用してデータベース レベルでエンティティをロックする必要があります。

必要なものを例示するために、2 つの属性 (id と名前) を持つ Person というエンティティ クラスと、1 つのインスタンス (Person#id) に対して同時に name 属性を更新するメイン プログラムを持つ単純なプロジェクトを作成しました。 = 1)。更新のために競合する 3 つのスレッドがあり、すべてが次の命令によってデータベース レベルで同期されます。

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

上記のコードを一度に 1 つのスレッドだけを使用すると、name 属性が更新され、他のすべてのスレッドはロックの取得を待機します。

ロックが発生した場合、Hibernate によって生成された SQL コードで視覚化でき、次のようになります。

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

または、session.load(...) が呼び出される行にブレークポイントを設定して、Eclipse IDE でのデバッグ中に視覚化することもできます (1 つのスレッドのみが次の命令に進み、他のすべてのスレッドは待機します)。

したがって、もう一度思い出してください。これは 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>
4

1 に答える 1

2

休止状態のHSQLDialectバグがあるようです。for update生成されたものには入れませんSQL: https://hibernate.atlassian.net/browse/HHH-7479

バグは最新のベータ版で解決されているようです: 4.3.0.Beta1

于 2013-04-30T18:28:41.720 に答える