8

最近、アプリケーションの ORM として c3p0 と共に hibernate を使い始めました。ただし、セッション ファクトリを閉じると、接続プール自体が閉じません。これは、セッションで何かを行うアプリケーションの唯一の場所です。

    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>

非常に短いアイドル接続の理由は、統合テストに合格するためにまだ見つけた唯一の方法であることに注意してください。彼らはセッションファクトリーを頻繁に開いたり閉じたりするので、いつも接続が不足しています。プロジェクトは始まったばかりなので、長期的にはあまり持続可能な戦略ではないと思います。

注意すべき「興味深い」ことは、初期接続プールを 1 に設定したにもかかわらず、c3p0 が開始時に 2 つの接続を開こうとすることです。私の推測では、閉じられない何らかの隠しセッションがどこかにあると思います (しかし、どこで私を打ち負かしますか)。

では、どうすれば厄介な接続プールを自分自身で閉じることができるのでしょうか?

追加情報: セッション ファクトリを作成および破棄する方法

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

0

私は同じ問題を抱えていて、このバグレポートで提供されている改善された (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 に答える