Hibernate/MySQL并发问题

aio*_*obe 6 mysql concurrency multithreading hibernate transactions

我用Hibernate(4.1.9.Final)和MySQL(14.14 Distrib 5.5.29,InnoDB表)获得了一个非常奇怪的结果:

当我使用一个线程将某些东西保存到数据库并尝试使用另一个线程获取它时,Hibernate并不总能找到该实体.(尽管事实上我正在提交事务并在打开加载会话之前关闭持久会话.)

一些观察:

  • 无法使用单线程程序重现这一点.

  • 可以在数据库中看到"缺失"实体,并且

  • 如果我重新启动应用程序,Hibernate 可以成功加载实体.

这是一个说明问题的SSCCE.(为简洁而省略进口):

public class StressTest {

    static SessionFactory sessionFactory;

    public static void main(String[] args) throws InterruptedException,
                                                     ExecutionException {

        // Configure Hibernate
        Configuration conf = new Configuration();
        conf.setProperty("hibernate.dialect",
                         "org.hibernate.dialect.MySQLInnoDBDialect");
        conf.configure();

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

        sessionFactory = conf.buildSessionFactory(serviceRegistry);

        // Set up producer / consumer
        BlockingQueue<Long> queue = new LinkedBlockingQueue<Long>();

        new Consumer(queue).start();
        new Producer(queue).start();
    }

}

class DummyEntity {
    long id;
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }
}
Run Code Online (Sandbox Code Playgroud)

生产者类(创建DummyEntities并保留它们).

class Producer extends Thread {

    BlockingQueue<Long> sink;

    public Producer(BlockingQueue<Long> sink) {
        this.sink = sink;
    }

    @Override
    public void run() {
        try {
            while (true) {

                Session session = StressTest.sessionFactory.openSession();

                DummyEntity entity = new DummyEntity();
                entity.setId(new Random().nextLong());

                session.beginTransaction();
                session.save(entity);
                session.getTransaction().commit();
                session.close();

                sink.put(entity.getId());
            }
        } catch (InterruptedException ignore) {
            System.exit(-1);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

消费者类(DummyEntities从数据库加载):

class Consumer extends Thread {

    BlockingQueue<Long> source;

    public Consumer(BlockingQueue<Long> source) {
        this.source = source;
    }

    @Override
    public void run() {

        try {
            while (true) {

                long entityId = source.take();

                Session session = StressTest.sessionFactory.openSession();
                Object entity = session.get(DummyEntity.class, entityId);
                session.close();

                if (entity == null) {
                    System.err.printf("Entity with id %d NOT FOUND", entityId);
                    System.exit(-1);
                }
            }
        } catch (InterruptedException ignore) {
            System.exit(-1);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,这是映射的xml DummyEntity.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping
    default-cascade="all"
    default-lazy="false">

    <class name="se.stresstest.DummyEntity">

        <id name="id" type="long">
            <generator class="assigned"/>
        </id>

    </class>

</hibernate-mapping>
Run Code Online (Sandbox Code Playgroud)

结果输出总是以如下结尾:

Entity with id -225971146115345 NOT FOUND
Run Code Online (Sandbox Code Playgroud)

有什么想法吗?

(这是以前的改良版本的问题.)

Pra*_*ati 0

MySQL5InnoDBDialect代替使用。