我正在尝试将Hibernate用于多线程应用程序,其中每个线程检索一个对象并尝试将其插入表中。我的代码如下所示。 我有每个线程的本地hibernate Session对象,并在每个InsertData中我做beginTransaction和commit。
我遇到的问题是很多次我得到“org.hibernate.TransactionException:不支持嵌套事务”
由于我刚接触休眠,我不知道我在做什么是正确的还是不正确?请告诉我在多线程应用程序中使用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=10
和c3p0.max_size=20
答案 0 :(得分:10)
对于每个线程的session-objects,只要你不在多个线程之间共享会话对象,你就可以了。
您收到的错误与您的多线程使用或会话管理无关。您对session.save()
的使用以及明确设置ID并不完全正确。
没有看到BlogPost
的映射很难说,但是如果你告诉Hibernate使用id
字段作为主键,并且你使用本机生成器作为主键,那么你需要做的就是:
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()
,在刷新会话之前不保证设置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()
设为私有或打包。如果另一个类显式设置ID(再次假设本机生成器,并且id为主键),则很可能是实现错误。