数据库连接池爆掉:Cannot create PoolableConnectionFactory

参考:解决spring+c3p0数据库连接一直增加的问题
这两天被数据库给搞疯了。经常报错,然后崩溃。如下

  15:13:46,765  INFO CpaBreportServiceImpl:906 - org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Io 异常: Got minus one from a read call)

找了好久,还是扒日志文件发现问题总是出在CpaBreportServiceImpl中,然后看CpaBreportServiceImpl这里类,发现其中有调用这个类的这个方法

package com.ufgov.util;

import java.sql.Connection;

import javax.sql.DataSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DBUtils {
    private static ApplicationContext applicationContext;

    /**
     * 从连接池中获取一个数据库连接
     */
    public static Connection getConnection() throws Exception{
        applicationContext = new ClassPathXmlApplicationContext("conf/applicationContext.xml");
        DataSource dataSource=applicationContext.getBean("dataSource",DataSource.class);        
        Connection conn=dataSource.getConnection();
        return conn;
    }
}

可以发现new ClassPathXmlApplicationContext("conf/applicationContext.xml")这行代码每一次都new一个ClassPathXmlApplicationContext,那就是重新创建一次连接池(其实不只是重新创建了一次连接池,Spring管理的所有bean及其它都重新加载了一次,可以看下日志)。这样连接池的连接马上就爆掉了(这里可以监控一下数据库的连接数目,使用语句select count(1) from v$session t where t.userName='数据库用户名' and t.program='JDBC Thin Client'可以发现每次new都会增长8个连接,这是因为BasicDataSource默认的maxActive为8,这个可以看源码。)。

那就使用spring容器来获取连接吧。
修改方式如下

package com.ufgov.util;

import java.sql.Connection;
import javax.sql.DataSource;

public class DBUtils
{
  public static Connection getConnection()
    throws Exception
  {
    DataSource dataSource = (DataSource)SpringContextUtil.getBean("dataSource");
    return dataSource.getConnection();
  }
}
package com.ufgov.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;

public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
     */

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        SpringContextUtil.applicationContext = applicationContext;
    }

    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static  T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static  T getBean(Class clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    private static void checkApplicationContext() {
        Assert.notNull(applicationContext,
                "applicaitonContext未注入,请在applicationContext.xml中定义SpringContextUtil");
    }
}

applicationContext.xml中做如下配置

    
    <bean class="com.ufgov.util.SpringContextUtil" lazy-init="false" />

你可能感兴趣的:(spring)