【问题标题】:program using hibernate does not terminate使用休眠的程序不会终止
【发布时间】:2014-03-05 21:55:39
【问题描述】:

我使用 Hibernate 创建了一个程序。

程序到达主函数结束,但程序仍在运行。

我想知道当SessionFactory 使用 Hibernate 版本 4.x 配置时是否会发生这种情况。

是不是配置的方式不对?


ma​​nual1_1_first_hibernate_apps.java

public static void main(String[] args) {

    args[0] ="list";
    if (args.length <= 0) {
        System.err.println("argement was not given");
        return;
    }

    manual1_1_first_hibernate_apps mgr = new manual1_1_first_hibernate_apps();

    if (args[0].equals("store")) {
        mgr.createAndStoreEvent("My Event", new Date());
    }
    else if (args[0].equals("list")) {
        mgr.<Event>listEvents().stream()
            .map(e -> "Event: " + e.getTitle() + " Time: " + e.getDate())
            .forEach(System.out::println);
    }
    Util.getSessionFactory().close();
}

private <T> List<T> listEvents() {
    Session session = Util.getSessionFactory().getCurrentSession();
    session.beginTransaction();
    List<T> events = Util.autoCast(session.createQuery("from Event").list());
    session.getTransaction().commit();
    return events;
}

Util.java

private static final SessionFactory sessionFactory;

/**
 * build a SessionFactory
 */
static {
    try {
        // Create the SessionFactory from hibernate.cfg.xml

        // hibernate version lower than 4.x are as follows
        // # it successful termination. but buildSessionFactory method is deprecated.
        // sessionFactory = new Configuration().configure().buildSessionFactory();

        // version 4.3 and later
        // # it does not terminate. I manually terminated.
        Configuration configuration = new Configuration().configure();
        StandardServiceRegistry serviceRegistry = 
                new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    }
    catch (Throwable ex) {
        // Make sure you log the exception, as it might be swallowed
        System.err.println("Initial SessionFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

/**
 * @return built SessionFactory
 */
public static SessionFactory getSessionFactory() {
    return sessionFactory;
}

程序终止并使用buildSessionFactory方法时的以下控制台日志sn-ps。

2 08, 2014 8:42:25 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH000030: Cleaning up connection pool [jdbc:derby:D:\Java\jdk1.7.0_03(x86)\db\bin\testdb]

但如果不使用已弃用的 buildSessionFactory 方法并终止(程序正在运行),则不会出现上述两行。

环境:

休眠 4.3.1 德比 JRE 1.8 IntelliJ IDEA 13

【问题讨论】:

  • 进程上的“kill -3”可能很方便
  • 谢谢。我不使用 kill 命令,但我注意到查看线程转储以查看您的评论。

标签: java hibernate


【解决方案1】:

我也遇到了同样的问题。我使用的是 Hibernate 4.1.1,一切正常。今天我升级到 Hibernate 4.3.1,突然我的应用程序不再终止。我进一步调查并注意到版本 4.1.1 对打开的 EntityManagerFactory 没有任何问题。这就是为什么我的应用程序总是终止的原因。 4.3.1 版不再是这种情况。所以我检查了我的应用程序并确保 EntityManagerFactory 在最后关闭(实际上我并没有真正关闭它)。问题解决了我。您真的确定您的应用程序中没有任何内容未打开吗?希望这会有所帮助。

马科斯

【讨论】:

    【解决方案2】:

    也许,我解决了这个问题。

    我看到 Util.getSessionFactory().close() 调用后的线程转储,一个名为“pool-2-thread-1”的线程状态为 TIMED_WAITING(停车)。

    下面的sn-ps转储

    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.0-b69 mixed mode):
    
    "DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x00000000020b9000 nid=0x3684 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "pool-2-thread-1" #15 prio=5 os_prio=0 tid=0x000000001bc27000 nid=0x3f0 waiting on condition [0x000000001ce6f000]
       java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000080be30a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:744)
    
    "derby.rawStoreDaemon" #14 daemon prio=5 os_prio=0 tid=0x000000001b059000 nid=0xa3c in Object.wait() [0x000000001ba1f000]
       java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000805f6190> (a org.apache.derby.impl.services.daemon.BasicDaemon)
        at org.apache.derby.impl.services.daemon.BasicDaemon.rest(Unknown Source)
        - locked <0x00000000805f6190> (a org.apache.derby.impl.services.daemon.BasicDaemon)
        at org.apache.derby.impl.services.daemon.BasicDaemon.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:744)
    
    "Timer-0" #13 daemon prio=5 os_prio=0 tid=0x000000001b08e800 nid=0x2160 in Object.wait() [0x000000001b6af000]
       java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000080608118> (a java.util.TaskQueue)
        at java.lang.Object.wait(Object.java:502)
        at java.util.TimerThread.mainLoop(Timer.java:526)
        - locked <0x0000000080608118> (a java.util.TaskQueue)
        at java.util.TimerThread.run(Timer.java:505)
    

    我认为原因是由 buildSessionFactory 方法创建的名为“pool-2-thread-1”的线程。

    通过比较两个 buildSessionFactory 方法,我注意到 ServiceRegistry 资源没有释放。

    程序通过释放成功终止。

    下面的代码,我补充一下。

    Util.java

    configuration.setSessionFactoryObserver(
            new SessionFactoryObserver() {
                @Override
                public void sessionFactoryCreated(SessionFactory factory) {}
                @Override
                public void sessionFactoryClosed(SessionFactory factory) {
                    ((StandardServiceRegistryImpl) serviceRegistry).destroy();
                }
            }
    );
    

    谢谢。

    【讨论】:

      【解决方案3】:

      我今天遇到了同样的问题,但我找到了另一个类似的解决方案:

      我在代码末尾插入了以下行:

      StandardServiceRegistryBuilder.destroy(serviceRegistry);
      

      还有塔达!程序结束。

      【讨论】:

        【解决方案4】:

        Hibernate 4.3.1 似乎引入了一个错误。我在我的应用程序中创建连接:

        EntityManagerFactory connection = Persistence.createEntityManagerFactory(...)
        

        但即使createEntityManagerFactory 方法因异常而失败,服务注册表仍保持打开状态。但是,正如您从上面的代码中看到的那样,我无法终止我的应用程序,因为该方法没有成功,变量connection 没有被分配(它是null),所以我不能调用connection.close() 会破坏服务注册表。看来这确实是一个错误,因为我如何能够在不求助于 hack 的情况下释放资源,例如使用 JPA 应用程序中的特定 Hibernate API?

        【讨论】:

          【解决方案5】:

          4.3.4.Final 中同样的问题。

          现在添加以下代码后,问题就消失了。

          public class Service {
          private SessionFactory factory;
          private ServiceRegistry serviceRegistry;
          
          public void initialize() throws Exception{
          
              Configuration configuration = new Configuration();
              configuration.configure("com/jeecourse/config/hibernate.cfg.xml");
          
              serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
                      configuration.getProperties()).build();
          
              factory = configuration.buildSessionFactory(serviceRegistry);
          
          }
          
          public void close() throws Exception{
              if(serviceRegistry!= null) {
                  StandardServiceRegistryBuilder.destroy(serviceRegistry);
              }
          }
          

          .....

          【讨论】:

            【解决方案6】:

            我今天也遇到了这个问题,我发现解决方案是,在你的主方法(或线程)结束时,你应该关闭你的会话工厂,比如:

            sessionFactory.close();
            

            然后,您的程序将正常终止。

            如果您在 main 方法中使用 JavaFX 8 添加:

            @Override
            public void stop() throws Exception {
                sessionFactory.close();
            }
            

            此方法将关闭会话工厂并在程序退出时销毁线程。

            【讨论】:

              【解决方案7】:

              我今天也遇到了这个问题,我发现解决方案如下:

              sessionFactory.close();
              

              如果你有的话会工作

              <property name="connection.pool_size">1</property>
              

              【讨论】:

                【解决方案8】:

                我有同样的问题,解决方法很简单,你必须将此属性添加到配置文件中

                    <property name="hibernate.c3p0.timeout">0</property>
                

                【讨论】:

                  【解决方案9】:

                  我正在使用带有 sqlite 3.20.1 的 hibenate 5.2.12,手动管理连接。就我而言,问题在于不仅实体管理器必须关闭,而且实体管理器工厂也必须关闭。

                  具有这些属性:

                  EntityManager entityManager;
                  EntityTransaction entityTransaction;
                  

                  这个sn-p在打开数据库和启动事务时使用:

                  EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, map);
                  entityManager = emf.createEntityManager(map);
                  entityTransaction = entityManager.getTransaction();
                  entityTransaction.begin();
                  

                  这个片段用于提交事务并关闭数据库:

                  entityTransaction.commit();
                  if ( entityManager.isOpen() ) {
                      entityManager.close();
                  }
                  EntityManagerFactory emf = entityManager.getEntityManagerFactory();
                  if ( emf.isOpen() ) {
                      emf.close();
                  }
                  

                  现在emf.close(); 我的应用程序按原样终止。

                  【讨论】:

                    【解决方案10】:

                    我的答案是针对 Hibernate 4.3+ 版本,我以自己的方式使用它。

                    使用 Hibernate 配置的 Spring Annotation 示例:

                    //Using AutoCloseable 1.7 feature here to close context and 
                    //suppress warning Resource leak: 'context' is never closed
                    //Creating AutoClosebale AbstractApplicationContext Object context
                    try (AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringAppConfig.class)) {
                    
                        SnacksMenu snacks = context.getBean(SnacksMenu.class);
                        System.out.println(snacks.toString());
                    
                        //Creating AutoClosebale SessionFactory Object factory
                        try (SessionFactory factory = getStandardServiceEnabledSessionFactory()){
                    
                            //Creating AutoClosebale Session Object session
                            try (Session session = factory.openSession()) {
                    
                                SessionCounter.analysisSession(session);
                                System.out.println("1: Opened Sessions under factory : " + SessionCounter.getOpenSessionsCount());
                    
                                Transaction transaction = session.beginTransaction();
                    
                                session.persist(snacks);
                                transaction.commit();
                    
                                System.out.println(session.isConnected());
                            }//Session Object session resource auto closed
                    
                        }//SessionFactory Object factory resource auto closed
                    
                        System.out.println("2: Opened Sessions under factory : " + SessionCounter.getOpenSessionsCount());
                    
                    }//AbstractApplicationContext Object context resource auto closed
                    

                    【讨论】:

                      【解决方案11】:

                      我们有多个数据库连接。

                      class ConnectionProviderFactory implements DataBaseConnectionProvider {
                      
                      private EnumMap<SystemInstance, Properties> connectionsConfigs = new EnumMap<>(SystemInstance.class);
                      private Map<SystemInstance, EntityManager> entityManagers = new HashMap<>();
                      private Map<SystemInstance, ConnectionPerSystemInstance> connections = new HashMap<>();
                      
                      
                      @Getter
                      private static class ConnectionPerSystemInstance {
                      
                          private String uuid = UUID.randomUUID().toString();
                      
                          private final SessionFactory sessionFactory;
                          private final SystemInstance systemInstance;
                      
                          private ConnectionPerSystemInstance(final SessionFactory sessionFactory, SystemInstance systemInstance){
                              this.sessionFactory = sessionFactory;
                              this.systemInstance = systemInstance;
                          }
                      
                          static ConnectionPerSystemInstance createConnection(Properties properties, SystemInstance systemInstance) {
                              StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
                              registryBuilder.applySettings(toMap(properties));
                              StandardServiceRegistry registry = registryBuilder.build();
                              MetadataSources sources = new MetadataSources(registry);
                              Metadata metadata = sources.getMetadataBuilder().build();
                              SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
                              return new ConnectionPerSystemInstance(sessionFactory, systemInstance);
                          }
                      
                          private static Map<String, String> toMap(Properties properties) {
                              Map<String, String> map = new HashMap<>();
                              for (String name : properties.stringPropertyNames()) {
                                  map.put(name, properties.getProperty(name));
                              }
                              return map;
                          }
                      
                          EntityManager getEntityManager() {
                              if(sessionFactory == null) {
                                  throw new IllegalStateException("Connection not initialized!");
                              }
                              return sessionFactory.createEntityManager();
                          }
                      
                          void close() {
                              if(sessionFactory == null) {
                                  throw new IllegalStateException("Connection not initialized!");
                              }
                              sessionFactory.close();
                          }
                      
                          @Override
                          public boolean equals(final Object o) {
                              if (this == o) return true;
                              if (o == null || getClass() != o.getClass()) return false;
                      
                              final ConnectionPerSystemInstance that = (ConnectionPerSystemInstance) o;
                      
                              return uuid.equals(that.uuid);
                          }
                      
                          @Override
                          public int hashCode() {
                              return uuid.hashCode();
                          }
                      }
                      
                      @PostConstruct
                      private void init() {
                          String testQuery = "select sysdate from dual";
                      
                          EntityManager e1TEST = connect(SystemInstance.TEST);
                      
                          EntityManager e1PROD = connect(SystemInstance.PROD);
                      
                          log.info("" + e1TEST.createNativeQuery(testQuery).getSingleResult());
                          log.info("" + e1PROD.createNativeQuery(testQuery).getSingleResult());
                      }
                      
                      @PreDestroy
                      private void clean() {
                          entityManagers.forEach((key, value) -> value.close());
                          connections.forEach((systemInstance, connectionPerSystemInstance) -> {
                              connectionPerSystemInstance.close();
                          });
                      }
                      
                      @Override
                      public EntityManager connect(final SystemInstance systemInstance) {
                      
                          if (Optional.ofNullable(entityManagers.get(systemInstance)).isPresent()) {
                              entityManagers.get(systemInstance);
                          }
                      
                          Properties properties = loadConnectionProperties(systemInstance);
                          ConnectionPerSystemInstance connection = ConnectionPerSystemInstance.createConnection(properties, systemInstance);
                          connections.put(systemInstance, connection);
                          entityManagers.put(systemInstance, connection.getEntityManager());
                      
                          return entityManagers.get(systemInstance);
                      }
                      
                      @Override
                      public void closeAllConnection() {
                          clean();
                      }
                      
                      private Properties loadConnectionProperties(SystemInstance systemInstance) {
                      
                          if (Optional.ofNullable(connectionsConfigs.get(systemInstance)).isPresent()) {
                              return connectionsConfigs.get(systemInstance);
                          }
                      
                          return tryLoadConnectionProperties(systemInstance);
                      }
                      
                      private Properties tryLoadConnectionProperties(final SystemInstance systemInstance) {
                          final String nameOfPropertyFile = getNameOfPropertyFile(systemInstance);
                          ClassPathResource classPathResource = new ClassPathResource(nameOfPropertyFile);
                          Properties properties = new Properties();
                          try {
                              properties.load(classPathResource.getInputStream());
                              addAdditionalConnectionSettings(properties);
                              connectionsConfigs.put(systemInstance, properties);
                          } catch (IOException e) {
                              log.error(e.getMessage(), e);
                              throw new RuntimeException(e.getMessage());                                                                             //TODO chanfe exception
                          }
                          return properties;
                      }
                      
                      private String getNameOfPropertyFile(SystemInstance systemInstance) {
                          if (systemInstance == SystemInstance.TEST)
                              return "db/db-test.properties";
                          if (systemInstance == SystemInstance.PROD)
                              return "db/db-prod.properties";
                          throw new IllegalArgumentException("Incorrect configuration");
                      }
                      
                      private void addAdditionalConnectionSettings(Properties properties) {
                          properties.putIfAbsent("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
                          properties.putIfAbsent("hibernate.c3p0.timeout", "0");
                      }
                      

                      }

                      在此示例中,我们有多个数据库,因此我们可以轻松关闭所有连接。

                      【讨论】:

                        【解决方案12】:

                        我遇到了同样的问题,原因是我们需要正确关闭资源。 尝试关闭 finally 块中的资源

                        try{
                        			Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
                        			sessionFactory = cfg.buildSessionFactory();;
                        			session = sessionFactory.openSession();
                        			transaction = session.beginTransaction();
                        			session.save(person);
                        			transaction.commit();
                        			}catch(Exception e){
                        				System.out.println("Exception occured. "+e.getMessage());
                        			}finally{
                        				if(session.isOpen()){
                        					System.out.println("Closing session");
                        					session.close();
                        				}
                        				if(!sessionFactory.isClosed()){
                        					System.out.println("Closing SessionFactory");
                        					sessionFactory.close();
                        				}
                        			}

                        【讨论】:

                          【解决方案13】:

                          确保您在整个程序中处理的 SessionFactory 实例相同。即,如果您要关闭您在程序中构建并打开 Session 的同一个 SessionFactory,则程序必须终止。问题部分的源代码并不能保证这一点,因此很麻烦。

                          请看以下简单直接的解决方案,

                          //your class definition
                          public static void main(String args[]) {
                                  SessionFactory sessionFactory = getSessionFactory();
                                  Session session = sessionFactory.openSession();
                                  session.beginTransaction().begin();
                                  session.save(yourEntity);
                                  session.beginTransaction().commit();
                                  session.close();
                                  sessionFactory.close();
                          }
                          
                          public static SessionFactory getSessionFactory() {
                                  Configuration cfg = new Configuration();
                                  cfg.configure("com/srees/hibernate.cfg.xml");
                                  SessionFactory sessionFactory = cfg.buildSessionFactory();
                                  return sessionFactory;
                              }
                          //your class def ends here
                          

                          【讨论】:

                            猜你喜欢
                            • 2014-06-24
                            • 1970-01-01
                            • 1970-01-01
                            • 2017-12-15
                            • 2011-09-19
                            • 2014-07-10
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多