2015-08-13 3 views
3

Im работает над java standAlone project. Мне нужно использовать спящий режим в приложении MultiThread, но я просто не могу понять, как правильно настроить его.Hibernate и multiThread Logic

Каждая нить имеет дело с тем же процессом других.

Все идет хорошо, когда я запускаю его в режиме Non-Async, но когда я вызываю то же самое, используя потоки, спящий режим просто не работает нормально.

Может кто-нибудь, пожалуйста, объясните мне, как правильно использовать Hibernate в автономном приложении MultiThread Java?

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

Ошибка приходит сюда

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

} 

идеи?

+0

с какой проблемой вы столкнулись? –

+0

проблема, что я не знаю, какой правильный дизайн для внедрения Hibernate в автономном приложении –

+0

Есть ли исключение? В чем разница в результатах между двумя вызовами? – carbontax

ответ

1

Проблема связана с переменными static Session. A SessionFactory является потокобезопасным и, вообще говоря, вам нужен только один (статический) экземпляр для каждой базы данных. A Session, с другой стороны, не является потокобезопасным и обычно создается (с использованием SessionFactory) и отбрасывается/закрывается на лету.

Чтобы решить непосредственную проблему, удалите переменную static Session sesion из вашего дао, а также «инлайн» в startTransmission и stopTransmission методы в методе findDespachoByTagId. Это гарантирует, что каждый поток, вызывающий findDespachoByTagId, создает и использует свой собственный экземпляр сеанса. Чтобы проанализировать текущую проблему, представьте два потока, вызывающих findDespachoByTagId одновременно. Теперь статической переменной сеанса будет присвоено значение дважды методом startTransmission. Это означает, что один экземпляр сеанса теряется почти сразу после его создания, а другой - двумя потоками одновременно. Нехорошо.

Но есть и другие проблемы: нет блоков finally, которые гарантируют, что транзакции будут закрыты, и соединения с базой данных будут выпущены (через закрытие сеансов). Кроме того, вы, вероятно, захотите использовать пул базы данных, поскольку тот, который предоставляется Hibernate, не подходит для производства. Я рекомендую вам взглянуть на HibHik: я создал этот проект, чтобы показать минимальное автономное приложение Java с использованием Hibernate с пулом базы данных (HikariCP), в котором используются рекомендуемые шаблоны и методы (в основном это показано в TestDbCrud.java). Используйте соответствующие компоненты в своем приложении, чем пишите многопоточные модульные тесты, чтобы проверить, что ваш уровень базы данных (DAO) работает нормально, даже в случае сбоя (например, когда база данных внезапно перестает быть доступной, поскольку сетевой кабель был отключен от сети).