8

我最近开始在我的应用程序中使用 hibernate 和 c3p0 作为 ORM。但是,当我关闭会话工厂时,连接池不会自行关闭!这是我的应用程序中唯一一个我对会话进行任何操作的地方。

    StatelessSession session = null;
    Transaction transaction = null;


    try {
        session = sessionFactory.openStatelessSession();
        transaction = session.beginTransaction();

        List<Thingy> list = session.getNamedQuery("getAvailableThingy").list();

        transaction.commit();
        return list;

    } catch (Exception error) { 
        if (transaction != null) {
            transaction.rollback();
        }
        throw error;
    } finally {
        if (session != null) {
            session.close();
        }
    }

这是我的hibernate.cfg.xml配置文件

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">


<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="javax.persistence.validation.mode">none</property>
        <property name="hibernate.connection.release_mode">after_transaction</property>

        <property name="hibernate.c3p0.minPoolSize">1</property>
        <property name="hibernate.c3p0.maxPoolSize">2</property>
        <property name="hibernate.c3p0.acquireIncrement">1</property>
        <property name="hibernate.c3p0.initialPoolSize">1</property>
        <property name="hibernate.c3p0.timeout">30</property>
        <property name="hibernate.c3p0.maxIdleTimeExcessConnections">5</property>
        <property name="hibernate.c3p0.idleConnectionTestPeriod">300</property>
    </session-factory>
</hibernate-configuration>

请注意,空闲连接非常短的原因是它是我发现的唯一让我的集成测试通过的方法。他们经常打开和关闭会话工厂,因此我总是用完连接。由于我们正处于项目的开始阶段,我想从长远来看这不是一个非常可持续的策略。

需要注意的“有趣”的事情是,尽管我将初始连接池设置为一个,但 c3p0 仍然尝试在启动时打开两个连接。我的猜测是某处有某种隐藏的会话不会关闭(但在哪里?打败我)。

那么我怎样才能让那个烦人的连接池自行关闭呢?

附加信息:我如何创建和销毁我的会话工厂

import static com.google.common.base.Preconditions.*;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Provides;


@Singleton 
public class PostgisConnection implements Provider<SessionFactory>, AutoCloseable {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final ConnectionInfo connectionInfo;
    private SessionFactory sessionFactory = null;

    @Inject 
    public PostgisConnection(ConnectionInfo connectionInfo) {
        this.connectionInfo = connectionInfo;
    }

    public AutoCloseable open() {
        checkState(sessionFactory == null, "Connections to postgis are already open");

        logger.info("Creating sessionFactory for connection to postgis: {}", connectionInfo.getJdbcUrl());
        sessionFactory = newPostgisSessionFactory(connectionInfo);

        return this;
    }

    @Override
    public void close() throws Exception {
        try {
            if (sessionFactory != null) {
                logger.info("Closing sessionFactory for postgis: {}", connectionInfo.getJdbcUrl());
                sessionFactory.close();
                checkState(sessionFactory.isClosed(), "Session factory should be closed at this point");
            }
        } catch (Exception error) {
            logger.error("Error closing SessionFactory", error);
        }
    }

    @Provides 
    public SessionFactory get() {
        return sessionFactory;
    }

    public static SessionFactory newPostgisSessionFactory(ConnectionInfo connectionInfo) {
        Configuration configuration = configurationWith(connectionInfo);
        return configuration.buildSessionFactory(registryFrom(configuration));
    }

    private static Configuration configurationWith(ConnectionInfo connectionInfo) {
        Configuration configuration = new Configuration();
        setConnectionInfo(connectionInfo, configuration);
        configuration.addURL(PostgisConnection.class.getResource("mapping.hbm.xml"));
        configuration.configure(PostgisConnection.class.getResource("hibernate.cfg.xml"));

        return configuration;
    }

    private static void setConnectionInfo(ConnectionInfo connectionInfo, Configuration configuration) {
        configuration.setProperty("hibernate.connection.url", connectionInfo.getJdbcUrl());
        configuration.setProperty("hibernate.connection.username", connectionInfo.getUsername());
        configuration.setProperty("hibernate.connection.password", connectionInfo.getPassword());
    }

    private static ServiceRegistry registryFrom(Configuration configuration) {
        return new ServiceRegistryBuilder()
                .applySettings(configuration.getProperties())
                .buildServiceRegistry();
    }

}
  • 休眠版本:4.1.10.Final
  • C3p0 版本:0.9.1.2
4

2 回答 2

14

我遇到了同样的问题并成功使用了此错误报告中提供的解决方法:

private void closeSessionFactory(SessionFactory factory) { 
   if(factory instanceof SessionFactoryImpl) {
      SessionFactoryImpl sf = (SessionFactoryImpl)factory;
      ConnectionProvider conn = sf.getConnectionProvider();
      if(conn instanceof C3P0ConnectionProvider) { 
        ((C3P0ConnectionProvider)conn).close(); 
      }
   }
   factory.close();
}

您必须引用 hibernate-c3p0-4.xx jar。

于 2013-07-17T14:46:01.623 回答
0

我遇到了同样的问题并成功使用了此错误报告中提供的 ehnanced(2014 年 1 月)解决方法:

private static boolean closeSessionFactoryIfC3P0ConnectionProvider(SessionFactory factory) {

    boolean done = false;
    if(factory instanceof SessionFactoryImpl) {
        SessionFactoryImpl sf = (SessionFactoryImpl)factory;
        ConnectionProvider conn = sf.getConnectionProvider();
        if(conn instanceof C3P0ConnectionProvider) { 
            ((C3P0ConnectionProvider)conn).close(); 
            try {
                Thread.sleep(2000); //Let give it time...it is enough...probably
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            done = true;
        }
        factory.close();
    }
    return done;

}

您必须引用 hibernate-c3p0-4.xx jar。

于 2014-01-05T06:41:17.817 回答