休眠和多线程逻辑 [英] Hibernate and multiThread Logic

查看:69
本文介绍了休眠和多线程逻辑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Java StandAlone项目.我需要在MultiThread应用程序中使用休眠模式,但我无法弄清楚如何正确设置它.

Im working on a java standAlone project. I need to use hibernate in a MultiThread application but i just cant figure it out how to set up this correctly.

每个线程都与其他线程处理相同的过程.

Each Thread deals with the same process of the others.

当我以非异步方式运行它时,一切都OK,但是当我使用线程调用相同的东西时,休眠只是无法正常工作.

Everything goes Ok when i run it in a Non-Async way, but when i call the same thing using threads, hibernate just don't work fine.

任何人都可以向我解释在多线程Java独立应用程序中使用Hibernate的正确方法是什么吗?

Can anyone please explain me what's the correct way to use Hibernate in a multiThread Java Stand-Alone App?

休眠实用程序

public class HibernateUtil {

private static final Session session;

static {
    try {
        SessionFactory sessionFactory;
        Properties properties = new Properties();
        properties.load(new FileInputStream("middleware.properties"));
        Configuration cfg = new Configuration().configure();
        cfg.addProperties(properties);
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
                .applySettings(cfg.getProperties()).build();
        sessionFactory = cfg.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
    } catch (IOException | HibernateException he) {
        JOptionPane.showMessageDialog(null, DataBaseMessage.CONNECTION_ERROR.getMessage(),              DataBaseMessage.CONNECTION_ERROR.getTitle(),JOptionPane.ERROR_MESSAGE);
        throw new ExceptionInInitializerError(he);          
    }  
}
public static Session getSession() {
    return session;
}

错误出现在这里

TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());

TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());

public synchronized List<TbHistoDespachos> ExractDespachoAndNotify(String data, String nombreConexion) {
    List<TbHistoDespachos> despachos = new ArrayList<>();
    String nombreConexionUpp = nombreConexion.toUpperCase();
    try {
        Document doc = convertStringToDocument(data);
        if (!doc.getRootElement().getChild("reply").getChild("readTagIDs")
                .getChildren().isEmpty()) {
            for (Element element : doc.getRootElement().getChild("reply").
                    getChild("readTagIDs").getChild("returnValue")
                    .getChildren()) {
                TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
                if (despacho != null) {
                    if(evaluateDespacho(nombreConexionUpp, despacho)){
                        despachos.add(despacho);
                    }
                }
            }
        }
    } catch (JDOMException | IOException ex) {
        JOptionPane.showMessageDialog(null, FilesMessageWarnings.NOTIFICATION_SAP_WARNING.
                getMessage().replace("&nombreConexion", nombreConexion).replace("&tagID", ""),
                FilesMessageWarnings.NOTIFICATION_SAP_WARNING.getTitle(), JOptionPane.WARNING_MESSAGE);
    }
    return despachos;
}

这是DAO

public class Dao {

private static Session sesion;
public static TbHistoDespachos findDespachoByTagId(String tagId) {
    TbHistoDespachos despacho = null;
    try {
        startTransmission();
        despacho = (TbHistoDespachos)sesion.createQuery("FROM TbHistoDespachos WHERE TAG_ID =:tagId")
                .setParameter("tagId", tagId)
                .uniqueResult();
        stopTransmission();
    } catch (HibernateException he) {
        System.out.println("error: " + he.getMessage());
        JOptionPane.showMessageDialog(null, DataBaseMessage.QUERY_ERROR.getMessage(),
                DataBaseMessage.QUERY_ERROR.getTitle(), JOptionPane.ERROR_MESSAGE);
    }
    return despacho;
}
private static void startTransmission() {

    sesion = HibernateUtil.getSession();
    sesion.getTransaction().begin();

}
private static void stopTransmission() {

    sesion.getTransaction().commit();
    sesion.getSessionFactory().getCurrentSession().close();
    sesion.clear();

}

有任何想法吗?

推荐答案

问题源于静态会话变量. SessionFactory 是线程安全的,通常来说,每个数据库只需要一个(静态)实例.另一方面, Session 不是线程安全的,通常是创建(使用 SessionFactory )并动态地关闭/关闭的.

The problem stems from static Session variables. A SessionFactory is thread-safe and, generally speaking, you only need one (static) instance per database. A Session, on the other hand, is not thread-safe and is usually created (using a SessionFactory) and discarted/closed on the fly.

要解决您眼前的问题,请从Dao中删除 static Session sesion 变量,然后在其中插入" startTransmission stopTransmission 方法 findDespachoByTagId 方法.这将确保每个调用 findDespachoByTagId 的线程创建并使用其自己的会话实例.要分析当前问题,请想象两个线程同时调用 findDespachoByTagId .现在,静态会话变量将通过 startTransmission 方法分配两次值.这意味着一个会话实例在创建之后几乎立即丢失,而另一个实例同时被两个线程使用.不好.

To solve your immediate problem, remove the static Session sesion variable from your Dao and also 'inline' the startTransmission and stopTransmission methods in the findDespachoByTagId method. This will ensure that each thread calling findDespachoByTagId creates and uses its own session instance. To analyze the current problem, imagine two threads calling findDespachoByTagId at the same time. Now the static session variable will be assigned a value twice by the startTransmission method. This means one session instance is lost almost immediatly after it was created while the other one is used by two threads at the same time. Not a good thing.

但是还有其他问题:没有 finally 块可以确保事务被关闭并且数据库连接被释放(通过关闭会话).另外,您可能要使用数据库池,因为Hibernate提供的数据库池不适合生产.我建议您看看 HibHik :我创建了这个项目,以展示一个最小的独立Java应用程序,它使用使用数据库池(HikariCP)休眠,该数据库使用推荐的模式和做法(主要显示在

But there are other problems too: there are no finally blocks that guarantee transactions are closed and database connections are released (via the closing of sessions). Also, you will probably want to use a database pool as the one provided by Hibernate is not suitable for production. I recommend you have a look at HibHik: I created this project to show a minimal stand-alone Java application using Hibernate with a database pool (HikariCP) that uses the recommended patterns and practices (mostly shown in TestDbCrud.java). Use the relevant parts in your application, than write multi-threaded unit-tests to verify your database layer (DAO) is working properly, even in the case of failure (e.g. when the database is suddenly no longer available because the network-cable was unplugged).

这篇关于休眠和多线程逻辑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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