我正在尝试将Hibernate用于多线程应用程序,其中每个线程都检索一个对象并将其插入表中。我的代码如下所示。
我每个线程都有本地 hibernate session 对象,在每个InsertData中,我都执行beginTransaction和commit。

我面临的问题是,很多时候我收到“org.hibernate.TransactionException:不支持嵌套事务”

由于我是新来的 hibernate 者,所以我不知道自己在做什么是否正确?请让我知道在多线程应用中使用 hibernate 的正确方法是什么,以及如何避免上述异常。

谢谢

public class Worker extends Thread {
private Session session = null;

Worker() {
    SessionFactory sf = HibernateUtil.getSessionFactory(); // Singleton
    session = sf.openSession();
    session.setFlushMode(FlushMode.ALWAYS);
}

public void run() {
    // Some loop which will run thousand of times
    for (....)
    {
        InsertData(b);
    }
    session.close();
}

// BlogPost Table has (pk = id AutoGenerated), dateTime, blogdescription etc.
private void InsertData(BlogPost b) {
    session.beginTransaction();
    Long id = (Long) session.save(b);
    b.setId(id);
    session.getTransaction().commit();
}
}

我的 hibernate 配置文件具有c3p0.min_size=10c3p0.max_size=20

最佳答案

使用每个线程 session 对象,只要您不在多个线程之间共享 session 对象,就可以了。

您收到的错误与多线程用法或 session 管理无关。您对session.save()的用法以及显式设置ID的方法不太正确。

看不到BlogPost的映射很难说,但是如果您已告诉Hibernate使用id字段作为主键,并且您正在使用 native 生成器作为主键,那么您要做的就是:

session.beginTransaction();
session.persist(b);
session.flush(); // only needed if flush mode is "manual"
session.getTransaction().commit();

Hibernate会为您填写ID,persist()会导致插入在事务范围内发生(save()不在乎事务)。如果刷新模式未设置为手动,则无需调用flush(),因为Transaction.commit()会为您处理。

请注意,使用persist(),不保证在刷新 session 之前设置BlogPost的ID,这对您在此处的用法很合适。

要优雅地处理错误:
try {
    session.beginTransaction();
    try {
        session.persist(b);
        session.flush(); // only needed if flush mode is "manual"
        session.getTransaction().commit();
    } catch (Exception x) {
        session.getTransaction().rollback();
        // log the error
    }
} catch (Exception x) {
    // log the error
}

顺便说一句,我建议将BlogPost.setId()设为私有(private)或可见。如果另一个类显式设置ID(再次假定 native 生成器和id为主键),则很可能是实现错误。

关于java - 如何在多线程应用程序中使用Hibernate?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18215370/

10-12 00:29
查看更多