1

データベース接続を閉じる際に問題に直面しています。以下のエラーが表示されます

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

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

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

JNDI を使用して接続を取得し、接続オブジェクトを返す DBUtilities.java ファイルを作成しました。この接続オブジェクトは、データベースのクエリ (プロシージャの呼び出し) のために他の Java クラスで使用され、終了すると閉じられます。ただし、ある程度の接続が成功した後、上記のエラーが発生します。私のクラスで書かれたコードを以下に示します。コードのどこが間違っているのか、データベースに問題があるのか​​ 誰でも教えてください。私はオラクル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);
    }
}
4

2 に答える 2

2

問題は、 finallyブロックcleanupがないコードにある可能性があります。

ResultSetまたはStatementcleanupのいずれかが例外をスローした場合、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);
           } 
    }
}

他の場所でも同様の問題が発生する可能性があります。

また、ここにあるその他のコードの一部は実際には必要ない可能性もあります。結果セットを閉じる前に「排出」しても何も得られないと思います。ステートメントを閉じると結果セットも閉じます。

于 2012-10-03T11:53:44.587 に答える
0

cleanUp メソッドは、事前に ResultSet や Statement も閉じようとすると、特定の SQLConnection を閉じることができない可能性があります。たとえば、ResultSet のクローズに失敗して SQLException がスローされた場合、接続をクローズすることさえせずに直接 catch ブロックにジャンプします。ログに接続を閉じる際のエラーはありますか?

この問題を回避するには、単一のもののみを閉じようとする専用の cleanUp メソッドを提供するか、sth を閉じようとするたびにラップします。独自の 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 に通知されず、プールに戻すことができません。そうすれば、制限に達するまで、プールはクローズされた接続でいっぱいになります。

于 2012-10-03T11:54:58.173 に答える