Hibernate / MySQL并发问题 [英] Hibernate / MySQL concurrency issue

查看:138
本文介绍了Hibernate / MySQL并发问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过Hibernate(4.1.9.Final)和MySQL(14.14 Distrib 5.5.29,InnoDB表)得到一个疯狂的奇怪结果

I get an insanely strange result with Hibernate (4.1.9.Final) and MySQL (14.14 Distrib 5.5.29, InnoDB table):

当我使用一个线程持久化数据库并尝试使用另一个线程提取它时,Hibernate并不总是找到实体。 (尽管事实上我正确地提交了事务并在打开加载会话之前关闭了持久会话。)

When I persist something to the database using one thread and try to fetch it using another thread, Hibernate does not always find the entity. (Despite the fact that I'm properly committing the transaction and closing the persist-session before opening the load-session.)

一些意见:


  • 无法使用单线程程序重现此问题。

  • I can not reproduce this using a single-threaded program.

可以查看数据库中的缺少实体,

I can see the "missing" entity in the database, and

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

If I restart the application Hibernate can successfully load the entity.

这里是一个说明问题的SSCCE。 (为简洁而省略输入):

Here's an SSCCE illustrating the problem. (Imports left out for brevity):

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; }
}

生产者类(创建 DummyEntities 并持久化它们。)

Producer class (creates DummyEntities and persists them).

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);
        }
    }
}

c $ c> DummyEntities 从数据库):

Consumer class (loads DummyEntities from database):

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);
        }
    }
}

DummyEntity 的xml。

<?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>

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

The resulting output always ends with something like:

Entity with id -225971146115345 NOT FOUND

为什么?

(这是以前的 question 。)

推荐答案

此行为可以与事务隔离模式的REPEATABLE READ,这恰好是InnoDB的默认事务隔离模式:

This behavior can be consistent with a transaction isolation mode of REPEATABLE READ, which happens to be the default transaction isolation mode for InnoDB:

http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read

如果您的应用程序逻辑依赖于能够在当前事务开始后查看其他事务中提交的数据的可重复读取(数据可以/将改变作为在其他事务中操作的结果) - 您应该将事务隔离设置为READ COMMITTED:

If your application logic is dependent upon being able to see data committed in other transactions after the current transaction was started - at the expense of repeatable reads (data can/will change as a result of manipulation in other transactions) - you should set the transaction isolation to READ COMMITTED:

http://dev.mysql.com/doc/refman/5.5/en /set-transaction.html#isolevel_read-committed

这篇关于Hibernate / MySQL并发问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆