【问题标题】:Hibernate and multiThread Logic休眠和多线程逻辑
【发布时间】:2015-11-05 21:09:22
【问题描述】:

我正在开发一个 java 独立项目。我需要在多线程应用程序中使用休眠,但我无法弄清楚如何正确设置它。

每个线程处理其他线程的相同进程。

当我以非异步方式运行它时一切正常,但是当我使用线程调用相同的东西时,休眠就不能正常工作。

谁能解释一下在多线程 Java 独立应用程序中使用 Hibernate 的正确方法是什么?

休眠实用程序

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

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

}

有什么想法吗?

【问题讨论】:

  • 你遇到了什么问题?
  • 我不知道在独立应用程序上实现 Hibernate 的正确设计是什么
  • 有异常吗?两次调用的结果有何不同?
  • 是的,主要是嵌套事务

标签: java multithreading hibernate hql


【解决方案1】:

问题源于static Session 变量。 SessionFactory 是线程安全的,一般来说,每个数据库只需要一个(静态)实例。另一方面,Session 不是线程安全的,通常是创建(使用SessionFactory)并在运行中丢弃/关闭。

要解决您当前的问题,请从您的 Dao 中删除 static Session sesion 变量,并在 findDespachoByTagId 方法中“内联”startTransmissionstopTransmission 方法。这将确保调用findDespachoByTagId 的每个线程都创建并使用自己的会话实例。分析当前问题,想象两个线程同时调用findDespachoByTagId。现在,startTransmission 方法将为静态会话变量赋值两次。这意味着一个会话实例在创建后几乎立即丢失,而另一个会话实例同时被两个线程使用。不是什么好事。

但也存在其他问题:没有finally 块可以保证事务已关闭并释放数据库连接(通过关闭会话)。此外,您可能希望使用数据库池,因为 Hibernate 提供的数据库池不适合生产。我建议你看一下HibHik:我创建了这个项目来展示一个最小的独立 Java 应用程序,它使用 Hibernate 和一个使用推荐模式和实践的数据库池 (HikariCP)(主要显示在 TestDbCrud.java 中)。使用应用程序中的相关部分,而不是编写多线程单元测试来验证您的数据库层 (DAO) 是否正常工作,即使在发生故障的情况下(例如,当数据库突然不再可用时,因为网络电缆是拔掉电源)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 2011-06-01
    • 2010-12-15
    • 1970-01-01
    相关资源
    最近更新 更多