使用C3P0的Hibernate在Oracle上工作正常但不关闭与MySQL 5.6的连接

时间:2013-11-13 06:11:32

标签: mysql oracle hibernate servlets

我正在使用Servlet 2.4,Hibernate 4.2.4 Final,c3p0 0.9.2.1,Tomcat 7.0.42,MySQL 5.6& JSP。

我已经使用Oracle 11gR2 DB完成了开发,但后来被要求切换到MySQL作为数据库。

我手边有一个非常不寻常的问题。

问题是为每个单个数据库请求创建了多个MySQL进程/连接,尽管发出SessionFactoryUtil.close();并且Oracle不是这种情况,但它们既不会关闭也不会返回到池中DB。

我在这两个不同的数据库上测试了完全相同的代码,即在执行功能/请求之后(例如:登录)

应用程序在使用Oracle(11gR2)进行测试时,数据库创建了一个连接,并将其用于此后的所有请求。 SELECT * FROM V$RESOURCE_LIMIT 给我以下输出
RESOURCE_NAME:流程
CURRENT_UTILIZATION:32
MAX_UTILIZATION:36
INITIAL_ALLOCATION:300
LIMIT_VALUE:300
无论有多少用户登录,连接池都会正常维护它。

现在另一方面,当在MySQL上运行相同的应用程序时:
我在MySQL上做了一个SHOW PROCESSLIST;,它显示了为每个请求创建的两个进程; c3p0成功终止一个连接,但另一个连接仍然存在,直到数据库崩溃,因为它超出了可用的最大连接数。

我的SessionFactoryUtil非常简单明了,如下所示: public class SessionFactoryUtil { private static SessionFactory sessionFactory;

public static SessionFactory getSessionFactory() {
    return sessionFactory = new Configuration().configure()
            .buildSessionFactory();//deprecated method not changed due to official reason
}

public Session getCurrentSession() {
    return sessionFactory.getCurrentSession();
}

public static void close() {
    if (sessionFactory != null) {
        sessionFactory.close();
    }
    sessionFactory = null;
}

public static SessionFactory getSessionFactory() { return sessionFactory = new Configuration().configure() .buildSessionFactory();//deprecated method not changed due to official reason } public Session getCurrentSession() { return sessionFactory.getCurrentSession(); } public static void close() { if (sessionFactory != null) { sessionFactory.close(); } sessionFactory = null; }

我的DAO方法如下

c3p0破坏连接的堆栈跟踪如下:

public User getUserByName(String userName) throws FetchException { User user = null; Session session = SessionFactoryUtil.getSessionFactory().getCurrentSession(); try { session.beginTransaction(); user = (User) session.createQuery("from User where userName = '" + userName + "'").uniqueResult(); } catch (Exception e) { logger.info("UserDaoImpl -> getUserByName() : Error : " +e); e.printStackTrace(); } finally { SessionFactoryUtil.close(); } return user;

我几乎已经阅读了与此特定场景相关的所有问题,但似乎没有任何工作,或者线程被中途放弃,或者我错过了一些东西;有人可以帮助我解决这个问题。

3 个答案:

答案 0 :(得分:1)

这段代码为我做了诀窍:

public static void close() {
if(sessionFactory instanceof SessionFactoryImpl) {
      SessionFactoryImpl sf = (SessionFactoryImpl)sessionFactory;
      ConnectionProvider conn = sf.getConnectionProvider();
      if(conn instanceof C3P0ConnectionProvider) { 
        ((C3P0ConnectionProvider)conn).close(); 
      }
   }
sessionFactory.close(); }

在那之前,Tomcat(正确地)抱怨每次热部署时内存泄漏。谢谢!

答案 1 :(得分:0)

一些想法:

1)您永远不会关闭您创建的会话(通过要求“当前会话”隐式)。这是一个直截了当的原因,为什么你可能会有一个最终超时的未回复的连接。

2)您正在将SessionFactory视为一个Session,然后构建并拆除整个事物(包括一个连接池)以获取和使用一个Connection。不太好。您的SessionFamily应该有很长的生命周期,您的会话应该是一次性的短期使用。

答案 2 :(得分:0)

我找到了我的奇怪问题的答案已经有一段时间了,我认为分享它会对大多数人有所帮助。

首先,我做错的几件事是...... 首先,我从hibernate 3.6迁移到4.2,并且这样做仍然使用了已弃用的buildSessionFactory()方法。

其次,我在DAO中的每个查询语句结束后使用SessionFactoryUtil.close(),这违背了使用连接池的目的。

最后,在执行语句后Oracle似乎成功关闭连接的奇怪问题,而MySql无法关闭它仍然是一个谜。 这个,我怀疑是因为我要求SessionFactoryUtil关闭最初由C3P0ConnectionProvider打开的连接(我认为这反过来导致连接泄漏)。

经过大量研究并四处寻找后,我重新编写了SessionFactoryUtil,如下所示......

public class SessionFactoryUtil {
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;

public static SessionFactory getSessionFactory() {
    Configuration configuration = new Configuration();
    configuration.configure();
    serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();        
    sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    return sessionFactory;
}

public static Session getCurrentSession() {
    if(sessionFactory == null){
        getSessionFactory();
    }
    return sessionFactory.getCurrentSession();
}

public static void close() {
    if(sessionFactory instanceof SessionFactoryImpl) {
          SessionFactoryImpl sf = (SessionFactoryImpl)sessionFactory;
          ConnectionProvider conn = sf.getConnectionProvider();
          if(conn instanceof C3P0ConnectionProvider) { 
            ((C3P0ConnectionProvider)conn).close(); 
          }
       }
    sessionFactory.close();
}

请注意,我的所有连接都是由 C3P0ConnectionProvider 打开的,因此使用 C3P0ConnectionProvider 本身关闭它是合乎逻辑的。

以下是我的hibernate.cfg.xml以及c3p0设置。

    <!-- Database connection settings -->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/application</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root</property>

    <property name="show_sql">true</property>
    <property name="format_sql">false</property>

     <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

     <!-- Enable Hibernate's automatic session context management -->
    <property name="hibernate.current_session_context_class">thread</property>
    <property name="hibernate.connection.release_mode">auto</property>

    <!-- Create or update the database schema on startup -->
    <property name="hibernate.hbm2ddl.auto">none</property>

    <!-- DEPRECATED -->
    <!--        <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> -->
    <!-- C3p0 connection pooling configuration -->
    <property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
    <property name="c3p0.unreturnedConnectionTimeout">600</property>
    <property name="c3p0.debugUnreturnedConnectionStackTraces">false</property>
    <!--        configuration pool via c3p0    -->
    <property name="c3p0.acquire_increment">1</property>   
    <property name="c3p0.idle_test_period">600</property>    
    <property name="c3p0.max_size">75</property>   
    <property name="c3p0.max_statements">5</property>   
    <property name="c3p0.min_size">5</property>   
    <property name="c3p0.timeout">600</property>
    <property name="c3p0.checkoutTimeout">6000000</property>

    <property name="c3p0.testConnectionOnCheckout">false</property>
    <property name="c3p0.testConnectionOnCheckin">true</property>   

    <!-- Mapping -->

</session-factory>

<!-- Database connection settings --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/application</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="show_sql">true</property> <property name="format_sql">false</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.connection.release_mode">auto</property> <!-- Create or update the database schema on startup --> <property name="hibernate.hbm2ddl.auto">none</property> <!-- DEPRECATED --> <!-- <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> --> <!-- C3p0 connection pooling configuration --> <property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property> <property name="c3p0.unreturnedConnectionTimeout">600</property> <property name="c3p0.debugUnreturnedConnectionStackTraces">false</property> <!-- configuration pool via c3p0 --> <property name="c3p0.acquire_increment">1</property> <property name="c3p0.idle_test_period">600</property> <property name="c3p0.max_size">75</property> <property name="c3p0.max_statements">5</property> <property name="c3p0.min_size">5</property> <property name="c3p0.timeout">600</property> <property name="c3p0.checkoutTimeout">6000000</property> <property name="c3p0.testConnectionOnCheckout">false</property> <property name="c3p0.testConnectionOnCheckin">true</property> <!-- Mapping --> </session-factory>

这又是我的DAO课程中的一种方法...



请注意,在我的DAO中,在finally块中,我不必再关闭我的连接了,我让c3p0处理连接池。

瞧......应用程序运行!!!在2小时的时间内,每天有超过2000笔交易点击 我希望这有助于像我这样的noob hibernate用户。