尽管有密切的陈述,数据库连接仍未关闭

时间:2012-10-03 11:26:04

标签: java connection pool

我在关闭数据库连接时遇到问题。我收到以下错误

=============================================== ===================================

267137 [http-8080-Processor23] FATAL com.abc.r2.dwrclasses.DBUtilities  - Failed to get a connection from DataSource JNDI/TPXSRUDB
org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted
    at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:103)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
    at com.abc.r2.dwrclasses.DBUtilities.getNativeConnection(DBUtilities.java:110)
    at com.abc.r2.dwrclasses.ProcedureCaller.callProcedure(ProcedureCaller.java:81)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.directwebremoting.impl.DefaultRemoter$1.doFilter(DefaultRemoter.java:740)
    at org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:744)
    at org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:593)
    at org.directwebremoting.dwrp.BaseCallHandler.handle(BaseCallHandler.java:90)
    at org.directwebremoting.servlet.UrlProcessor.handle(UrlProcessor.java:120)
    at org.directwebremoting.servlet.DwrServlet.doPost(DwrServlet.java:141)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
    at com.oracle.determinations.web.platform.util.CharsetFilter.doFilter(CharsetFilter.java:46)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
    at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
    at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:619)
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
    at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:756)
    at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
    ... 42 more

=============================================== ====================================

我编写了一个DBUtilities.java文件,该文件使用JNDI获取连接并返回连接对象。然后,此连接对象在其他java类中用于查询数据库(调用过程),然后在完成时关闭。但是,经过一定量的成功连接后,它会给出上述错误。我班上写的代码如下。任何人都可以让我知道代码中的错误或数据库是否有问题。我正在使用oracle 10g。

=============================================== ==========================================

package com.abc.r2.dwrclasses;


/*
 * Utilites.java
 *
 * Created on 08 July 2004, 11:55
 */



import java.sql.*;

import javax.sql.*;
import javax.naming.*;

import java.util.*;

import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.apache.commons.dbutils.DbUtils;

import com.ibm.ws.rsadapter.jdbc.WSJdbcConnection;
import com.ibm.ws.rsadapter.jdbc.WSJdbcUtil;


/**
 * Abstract class containing useful database methods.
 * @author Rajan Panchal
 */
public abstract class DBUtilities {

    private static final Logger log = Logger.getLogger(DBUtilities.class);

    private static Context initCtx; // Initial context
    private static Context envCtx;  // Environment context
    static ResourceBundle rb;
    static String appServer;
    DataSource ds;
    // Only get the JNDI context once, it's expensive.
    /* Get the JNDI context depending upon the configuration stored in appconfiguration.properties file in configuration folder */
    static {
        try {
                rb = ResourceBundle.getBundle("configuration.queries");
                appServer = rb.getString("APP_SERVER");
                log.debug("Application Server: "+appServer);
            if(appServer.equalsIgnoreCase("TOMCAT")){        
                initCtx = new InitialContext();        
                envCtx  = (Context)initCtx.lookup("java:/comp/env");
            }else if(appServer.equalsIgnoreCase("WEBSPHERE")){
                Hashtable env = new Hashtable();
                env.put("java.naming.factory.initial","com.ibm.websphere.naming.WsnInitialContextFactory");
                System.out.println("INITIAL_CONTEXT_FACTORY: com.ibm.websphere.naming.WsnInitialContextFactory");
                initCtx = new InitialContext(env);
            }
        } catch (javax.naming.NamingException e) {
                log.fatal("Failed to get JNDI context on "+appServer, e);
                throw new RuntimeException(e);
        }
    }

    /**
     *  Get a JDBC connection
     * @param jndiName the JNDI name of the datasource
     * @return a Connection to the datasource
     */
    public static Connection getConnection(String jndiName) {
        int maxtry = 10;
        int DBConnectTry = 0;
        while( DBConnectTry++ < maxtry){
            log.info("trying to connect:"+DBConnectTry);
        try {
            if(appServer.equalsIgnoreCase("TOMCAT")){               
                DataSource ds = (DataSource)envCtx.lookup(jndiName);
                log.debug("Returning connection object for "+appServer);
            return ds.getConnection();
            }else if(appServer.equalsIgnoreCase("WEBSPHERE")){
                DataSource ds = (DataSource)initCtx.lookup(jndiName);
                log.debug("Returning connection object for "+appServer);
                return ds.getConnection();
            }
        } catch (javax.naming.NamingException e) {
            log.fatal("JNDI lookup  failed for DataSource "+jndiName, e);
            throw new RuntimeException(e);
        } catch (SQLException e) {
            log.fatal("Failed to get a connection from DataSource "+jndiName, e);
            log.info("Wait for 1 sec...");
             Long WaitTime = System.currentTimeMillis()+1000L;
             while(System.currentTimeMillis()<WaitTime){

           }
            log.info("Wait Over retrying...");            
        }
        }
        return null;

    }
/* This method returns the native connection for executing the pl/sql  procedure with array descriptors.*/    
    public static Connection getNativeConnection(String jndiName) {
        int maxtry = 10;
        int DBConnectTry = 0;
        Connection conn;
        while( DBConnectTry++ < maxtry){
            log.info("trying to connect:"+DBConnectTry);
        try {
                if(appServer.equalsIgnoreCase("TOMCAT")){
                    DataSource ds = (DataSource)envCtx.lookup(jndiName);
                    conn = ds.getConnection();
                    if (conn instanceof org.apache.commons.dbcp.DelegatingConnection)      { 
                        log.debug("detected apache commons dbcp datasource");          
                        conn = ((org.apache.commons.dbcp.DelegatingConnection) conn).getInnermostDelegate();      
                    }
                    return conn;
                }else if(appServer.equalsIgnoreCase("WEBSPHERE")){
                    DataSource ds = (DataSource)initCtx.lookup(jndiName);
                    conn = (Connection) WSJdbcUtil.getNativeConnection((WSJdbcConnection)ds.getConnection());                   
                    return conn;
                }
        } catch (javax.naming.NamingException e) {
            log.fatal("JNDI lookup  failed for DataSource "+jndiName, e);
            throw new RuntimeException(e);
        } catch (SQLException e) {
            log.fatal("Failed to get a connection from DataSource "+jndiName, e);
            log.info("Wait for 1 sec...");
             Long WaitTime = System.currentTimeMillis()+1000L;
             while(System.currentTimeMillis()<WaitTime){

           }
            log.info("Wait Over retrying...");            
        }
        }
        return null;

    }
    /**
     * Utility method to close a connection, and/or a statement, and/or a resultset
     * @param con Connection, or null
     * @param stmt Statement, or null
     * @param rs ResultSet, or null
     */
    public static void cleanUp(Connection con, Statement stmt, ResultSet rs) {
        try {
            if (rs != null) {
                while (rs.next()) // Drain the resultset.
                    ;
                rs.close();
            }

            if (stmt != null)
                stmt.close();

            if (con != null)
                con.close();
        } catch (SQLException e) {
            log.error("Failed to close connection", e);
        }
    }

    /**
     * Convert a ResultSet to a List of Maps
     * This enables the results to be processed
     * using the JSTL forEach tag.
     * @param rs the ResultSet to convert
     * @throws SQLException may be thrown by ResultSet operations
     * @return the converted ResultSet
     */
    @SuppressWarnings("unchecked")
    public static List convertResultSet(ResultSet rs) throws SQLException {
        try {
            NDC.push("convertResultSet");
            log.debug("start");

            // Get column names
            ResultSetMetaData rsmd = rs.getMetaData();
            int numberOfColumns = rsmd.getColumnCount();
            log.debug("Column Count is "+numberOfColumns);
            String[] names = new String[numberOfColumns];
            int[] types = new int[numberOfColumns];
            for (int i = 0; i < names.length; ++i) {
                names[i] = rsmd.getColumnName(i+1);
                types[i] = rsmd.getColumnType(i+1);
                log.debug("  Name="+names[i]);
            }

            List l = new LinkedList();

            // Loop through the rows
            while (rs.next()) {
                log.debug("Processing row "+l.size());
                Map m = new HashMap();

                // Loop through the columns
                for (int i = 0; i < names.length; ++i) {
                    Object o;
                    switch(types[i]) {
                        case Types.DATE:
                            o = rs.getTimestamp(i+1);
                            break;
                        default:
                            o = rs.getString(i+1);
                    }
                    log.debug("  "+names[i]+"='"+o+"'");
                    /*
                    if (o == null)
                        o = "&nbsp;";
                    */
                    m.put(names[i], o);
                }

                // Add the map to the list
                l.add(m);
                log.debug("done");
            }

            return l;
        } finally {
            NDC.pop();
        }
    }

    @SuppressWarnings("unchecked")
    public static void formatDates(List rows, java.text.SimpleDateFormat fmt) {
        Iterator it1 = rows.iterator();
        while (it1.hasNext()) {
            Map m = (Map)it1.next();
            List names = new LinkedList();
            Iterator it2 = m.entrySet().iterator();
            while (it2.hasNext()) {
                Map.Entry e = (Map.Entry)it2.next();
                if (e.getValue() instanceof Timestamp) {
                    names.add(e.getKey());
                }
            }

            it2 = names.iterator();
            while(it2.hasNext()) {
                String name = (String)it2.next();
                Timestamp t = (Timestamp) m.get(name);
                String s = fmt.format(t);
                m.put(name,s);
            }

        }

    }

    /**
     * Generate dummy results as a List of Maps
     *
     * @param columns A string array containing the required columns names
     * @param rows    The number of rows to generate
     * @return The data as a List of Maps
     */
    @SuppressWarnings("unchecked")
    public static List generateTestData(String[] columns, int rows) {

        try {
            NDC.push("generateTestData");

            List l = new LinkedList();

            for (int row = 1; row <= rows; ++row) {
                Map m = new HashMap();

                // Loop through the columns
                for (int i = 0; i < columns.length; ++i) {
                    String s = columns[i]+" "+row;
                    m.put(columns[i], s);
                }

                // Add the map to the list
                l.add(m);
            }

            return l;
        } finally {
            NDC.pop();
        }
    }


    /**
     * retrieves just the error code from an oracle message
     */
    public static String parseOracleError(String errCode, String errMsg) {

        int start = 0;
        int end = 0;
        start = errMsg.indexOf(errCode);
        end = errMsg.indexOf(":", start);
        return errMsg.substring(start, end);
    }

     /**Close a <code>Connection</code>, <code>Statement</code> and
     * <code>ResultSet</code> cleanly.
     */
    public static void close(Connection conn, Statement stmt, ResultSet rs) {
        try {
            DbUtils.close(rs);
            DbUtils.close(stmt);
            DbUtils.close(conn);
        } catch (SQLException sqlEx) {
            log.error("Failed to close database objects cleanly.", sqlEx);
        }
    }

    /**Close a <code>Connection</code> and <code>Statement</code> cleanly.
     */
    public static void close(Connection conn, Statement stmt) {
        try {
            DbUtils.close(stmt);
            DbUtils.close(conn);
        } catch (SQLException sqlEx) {
            log.error("Failed to close database objects cleanly.", sqlEx);
        }
    }

    /**Close a <code>Connection</code> and <code>Statement</code> quietly.
     */
    public static void closeQuietly(Connection conn, Statement stmt) {
        DbUtils.closeQuietly(stmt);
        DbUtils.closeQuietly(conn);
    }

    /**Close a <code>Connection</code>, <code>Statement</code> and 
     * a <code>ResultSet</code> quietly.
     */
    public static void closeQuietly(Connection conn, Statement stmt, ResultSet rst) {
        DbUtils.closeQuietly(rst);
        DbUtils.closeQuietly(stmt);
        DbUtils.closeQuietly(conn);
    }
}

2 个答案:

答案 0 :(得分:2)

问题可能出在cleanup代码中,您没有最终阻止。

如果ResultSetStatement清理中的任何一个抛出异常,con.close()将不会发生。

尝试类似(未经测试)的内容:

public static void cleanUp(Connection con, Statement stmt, ResultSet rs) {
    try {
        if (rs != null) {
            while (rs.next()) // Drain the resultset.
                ;
            rs.close();
        }

        if (stmt != null)
            stmt.close();

    } catch (SQLException e) {
        log.error("Failed to close statement", e);
    }
    finally {
        if (con != null)
           try {
               con.close();
           } catch (SQLException e) {
               log.error("Failed to close connection", e);
           } 
    }
}

其他地方可能会发生类似的问题。

您可能实际上并不需要其他一些代码。我不认为在关闭结果集之前“排空”结果集会产生任何结果,关闭语句也会关闭结果集。

答案 1 :(得分:0)

如果尝试同时关闭ResultSet和/或Statement,则cleanUp方法可能无法关闭给定的SQLConnection。例如如果关闭ResultSet失败并抛出SQLException,它将直接跳转到catch块,甚至没有尝试关闭连接。关闭日志中的连接时是否有错误?

要避免这个问题,要么提供专用的cleanUp方法,这些方法只会尝试关闭单个事物或包装每个尝试关闭某个事物。在它自己的try / catch块中。相同的建议适用于各种close和closeQuietly方法。

//编辑

此代码部分很可能有害。在getNativeConnection(String jndiName)中:

DataSource ds = (DataSource)envCtx.lookup(jndiName);
conn = ds.getConnection();
if (conn instanceof org.apache.commons.dbcp.DelegatingConnection) { 
   log.debug("detected apache commons dbcp datasource");          
   conn = ((org.apache.commons.dbcp.DelegatingConnection)conn).getInnermostDelegate();      
}

DelegatingConnection似乎是一个处理连接池的代理。当您解开“本机”连接时,在连接关闭时不会通知DelegatingConnection-Proxy,并且无法将其返回到池中。这样,游泳池就会填满关闭的连接,直到达到极限。