使用hibernate的程序不会终止

时间:2014-02-08 11:37:01

标签: java hibernate

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

程序到达主函数端,但程序正在运行。

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

配置错误的方法是什么?


manual1_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方法。

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方法并终止(程序正在运行),则不会出现上述两行。

环境:

 Hibernate 4.3.1
 DERBY
 JRE 1.8
 IntelliJ IDEA 13

13 个答案:

答案 0 :(得分:46)

我今天也遇到了这个问题,我发现解决方案是,在你的主方法(或线程)的最后,你应该关闭你的Session Factory,如:

sessionFactory.close();

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

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

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

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

答案 1 :(得分:13)

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

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

StandardServiceRegistryBuilder.destroy(serviceRegistry);

和Ta-dah!该计划结束。

答案 2 :(得分:7)

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

.....

答案 3 :(得分:5)

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

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

以下代码段转储

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

感谢。

答案 4 :(得分:4)

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

EntityManagerFactory connection = Persistence.createEntityManagerFactory(...)

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

答案 5 :(得分:4)

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

sessionFactory.close();
如果你有

会有效

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

答案 6 :(得分:2)

我正在使用hibenate 5.2.12和sqlite 3.20.1,手动管理连接。就我而言,问题是不仅要关闭实体经理,还要关闭实体经理工厂。

具有以下属性:

EntityManager entityManager;
EntityTransaction entityTransaction;

打开数据库并开始交易时使用此代码段:

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();我的应用程序应该终止。

答案 7 :(得分:1)

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

马科斯

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

我的答案是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

答案 10 :(得分:0)

我们有多个数据库连接。

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

}

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

答案 11 :(得分:0)

我遇到了同样的问题,原因是我们需要正确关闭资源。 尝试在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();
				}
			}

答案 12 :(得分:0)

确保在整个程序中使用相同的SessionFactory实例。即,如果您要关闭在程序中构建并打开会话的同一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