如何在多线程应用程序中使用Hibernate? [英] How to use Hibernate in a multi threaded application?

查看:316
本文介绍了如何在多线程应用程序中使用Hibernate?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将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);

$ b $ public void run(){
//某些循环将运行数千次
(...)
{
InsertData(b);
}
session.close();
}

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


$ / code $ / pre
$ b $我的hibernate配置文件有 c3p0.min_size = 10 c3p0.max_size = 20

解决方案

使用session-objects-per-thread,只要你不在多个线程之间共享会话对象,你就可以。



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



你的 BlogPost 的映射很难说,但是如果你告诉Hibernate使用 id 字段作为主键,并且你使用的是本地生成器的主键,你所需要做的就是这样:



$ $ $ $ $ $ $ c $ session.beginTransaction() ;
session.persist(b);
session.flush(); //仅当刷新模式为手动时才需要
session.getTransaction()。commit();

Hibernate会为您填写ID, persist()将导致插入发生在事务的范围内( save()不关心事务)。如果你的flush模式没有设置为manual,那么你不需要调用 flush()作为 Transaction.commit() persist()时,BlogPost的ID不能保证直到会话刷新为止,这对您在这里的使用很好。



优雅地处理错误:

  try {
session.beginTransaction();
尝试{
session.persist(b);
session.flush(); //仅当刷新模式为手动时才需要
session.getTransaction()。commit();
} catch(Exception x){
session.getTransaction()。rollback();
//记录错误
}
} catch(异常x){
//记录错误
}

顺便提一下,我建议让> BlogPost.setId()私有或包可见。如果另一个类明确地设置了ID(再次假定本地生成器和ID为主键),那么这很可能是实现错误。


I am trying to use Hibernate for a multi threaded application wherein each thread retrieves an object and tries to insert it into a table. My code looks like below. I have local hibernate Session objects per thread and in each InsertData I do beginTransaction and commit.

The problem I am facing is that many times I get "org.hibernate.TransactionException: nested transactions not supported"

Since I am new to hibernate I don't know if what I am doing is correct or not? Please let me know what is the correct way to use hibernate in multi threaded app and how to avoid the above mentioned exception.

Thanks

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

My hibernate config file has c3p0.min_size=10 and c3p0.max_size=20

解决方案

With session-objects-per-thread, as long as you are not sharing session objects between multiple threads, you will be fine.

The error you are receiving is unrelated to your multithreaded usage or your session management. Your usage of session.save() as well as explicitly setting the ID is not quite right.

Without seeing your mapping for BlogPost its hard to tell, but if you have told Hibernate to use the id field as the primary key, and you are using the native generator for primary keys, the all you need to do is this:

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

Hibernate will fill in the ID for you, persist() will cause the insert to happen within the bounds of the transaction (save() does not care about transactions). If your flush mode is not set to manual then you don't need to call flush() as Transaction.commit() will handle that for you.

Note that with persist(), the BlogPost's ID is not guaranteed to be set until the session is flushed, which is fine for your usage here.

To handle errors gracefully:

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
}

By the way, I suggesting making BlogPost.setId() private, or package visible. It is most likely an implementation error if another class sets the ID explicitly (again assuming native generator, and id as primary key).

这篇关于如何在多线程应用程序中使用Hibernate?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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