Hibernate and multiThread Logic

不想你离开。 提交于 2021-01-27 10:43:55

问题


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.

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.

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

Hibernate Util

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

The Error comes here

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

Here is the 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();

}

ANY IDEAS?


回答1:


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.

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.

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).



来源:https://stackoverflow.com/questions/31979089/hibernate-and-multithread-logic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!