连接池挂着java多线程程序

时间:2017-02-13 10:06:07

标签: java multithreading oracle connection-pooling ojdbc

我有一个24/7 java应用程序(jdk1.5.0_19),它是多线程的,使用OJDBC5作为oracle 11g(11.2.0.3)的通信。在验证线程的内容之后,每个线程调用要准备的可调用语句,然后执行以将数据插入到表中。现在在初始化时有一个Total JDBC 20 Connections。有一段时间它没有问题。

但是最近有一个实例,它在DB中执行可调用语句时才挂起。

2017-02-06 13:03:39,855 [Thread-1] INFO  QCCOM_SocketWorker run  - Worker thread launched.
2017-02-06 13:03:39,856 [Thread-1] INFO  QCCOM_Socket recvMessage  
2017-02-06 13:03:39,856 [Thread-1] INFO  QCCOM_SocketWorker recvRequest 
2017-02-06 13:03:39,856 [Thread-1] INFO  ProcessHandler invoke  
2017-02-06 13:03:39,856 [pool-1-thread-1] INFO  HandlerValidator validateRequest 
2017-02-06 13:03:39,857 [pool-1-thread-1] INFO  ProcessHandler process  - Processing request...
2017-02-06 13:03:39,857 [pool-2-thread-1] INFO  JDBCHelper call  - Atempting to retrieve connection.
2017-02-06 13:03:39,857 [pool-2-thread-1] INFO  JDBCHelper call  - Connection successfully retrieved
2017-02-06 13:03:39,857 [pool-1-thread-1] INFO  JDBCHelper getConnection  - Conn : oracle.jdbc.driver.LogicalConnection@4f064f06
2017-02-06 13:03:39,858 [pool-1-thread-1] INFO  JDBCServiceImpl insertBP  - Calling insert transaction stored procedure..
2017-02-06 13:03:43,856 [Thread-1] INFO  ProcessHandler invoke  - Worker Thread Timed out
2017-02-06 13:03:43,857 [Thread-1] DEBUG ProcessHandler invoke  - [java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:226), java.util.concurrent.FutureTask.get(FutureTask.java:100), ....ProcessHandler.invoke(ProcessHandler.java:114), com.qcom.qcm.qccom.QCCOM_SocketWorker.dispatch(QCCOM_SocketWorker.java:88), com.qcom.qcm.qccom.QCCOM_SocketWorker.run(QCCOM_SocketWorker.java:126)]
2017-02-06 13:03:43,857 [Thread-1] INFO  QCCOM_SocketWorker run  - Worker thread shutdown. 
2017-02-06 13:03:55,661 [pool-1-thread-1] INFO  JDBCServiceImpl insertBP  - Callable Statement successfully closed!
2017-02-06 13:03:55,661 [pool-1-thread-1] INFO  JDBCServiceImpl insertBP  - Connection successfully closed!
2017-02-06 13:03:55,662 [pool-1-thread-1] INFO  ProcessHandler process  - Connection successfully closed!

通常交易发生的时间少于200毫秒。

2017-02-06 13:03:39,858 [pool-1-thread-1] INFO JDBCServiceImpl insertBP - 调用插入事务存储过程..

但是在上面的例子中,我们对insert的执行挂起了。

请参阅下面的代码(JDBCServiceImpl insertBP)。

public synchronized void insertBP(String A, BigDecimal Num, Date Date) throws SQLException{
    CallableStatement cs = null;
    logger.info("Calling insert transaction stored procedure..");
    try{
        cs = (CallableStatement) conn.prepareCall("{"+sql+"}");
        cs.setString(1, tnxType);
        cs.setBigDecimal(2, Num);
        cs.setTimestamp(3, new Timestamp(Date.getTime()));

        cs.execute();
    } catch (SQLException sqlEx){           
        String strMessageContents = StringUtil.getFailedMessageContents(A, Num, Date);
        String strErrorMessage = "Failed to insert ";
        logger.fatal(strErrorMessage);
        aUtil.emailFatal;
        throw sqlEx;
    } finally {
        if (null!=cs){
            cs.close();
            logger.info("Callable Statement successfully closed!");
        }
        if (null!=conn){
            conn.close();
            logger.info("Connection successfully closed!");
        }
    }
}

不知怎的,它挂起在cs.execute ...然后工作线程超时出现并杀死整个事务但不知何故它不会杀死已经启动的可调用语句。

我还有一个故障转移代码,用于杀死主连接,通过这种方法,整个连接被终止,导致成功查杀。

2017-02-06 13:03:54,661 [pool-1-thread-1] INFO JDBCServiceImpl insertBP - Callable Statement已成功关闭!

代码如下

    if (Util.IsOffline){
    logger.info("App is Offline attempting to reestablish connection.");
    Util.destroyHelper();
    logger.info("Previous Connection Pool Destroyed...");
    logger.info("Reinitializing Connection Pool ...");
    try {
        AppJDBCHelper helper = AppJDBCHelper.getInstance();
        if (null != helper){
            logger.info("Connected to Schema: "+helper.getSchema());
            logger.info("Connection Pool initialized ...");
            Util.IsOffline = false;
            logger.info("App has reestablished connection.");
        }
        if (null == helper){
            logger.fatal("Failed to get database connection pool ...");
            Util.destroyHelper();
        }
    } catch (SQLException e){
        logger.fatal("Failed to connect to database ...");
        logger.debug(Arrays.toString(e.getStackTrace()));
        System.out.println(" \n >>> ERROR: Failed to connect to database ..."); 
        Util.destroyHelper();
    }
}

Util的附加代码

public void destroyHelper(){
    AppJDBCHelper helper = null;
    try {
        helper = AppJDBCHelper.getInstance();
        helper.destroy();
    } catch (SQLException e) {
        logger.fatal(e);
        logger.debug(Arrays.toString(e.getStackTrace()));
    }       
}

AppJDBCHelper的附加代码

public void destroy() throws SQLException{
    DBConnectionPool pool = new DBConnectionPoolImpl();
    pool.closeConnectionPool(ods);
    helper = null;
    logger.info("AppJDBCHelper destroy() success...");
}

这两台机器位于同一个开关中,因此网络摩擦较小。 并且在检查过程中没有网络问题。此外,DB Listener已启动并准备接受事务。

所以这里我的主要问题是发生了什么,并且可调用语句悬而未决。

1 个答案:

答案 0 :(得分:0)

一种可能的方法是自下而上,先检查数据库中是否存在问题。 如果您使用的是Oracle 11g,则会有一个很好的更改,您还拥有ASH

的许可证

使用以下查询检查数据库(或联系您的DBA),您可以在其中参数化时间内容和连接池DBUSER。 (如果问题出现在过去的历史记录中,请切换到包含较长时间间隔的表dba_hist_active_sess_history

select  
SAMPLE_TIME, SQL_EXEC_ID, SESSION_ID, SESSION_SERIAL#, SQL_ID, TOP_LEVEL_SQL_ID, SQL_OPNAME,
PLSQL_ENTRY_OBJECT_ID, EVENT, BLOCKING_SESSION_STATUS, BLOCKING_SESSION, BLOCKING_SESSION_SERIAL#
select * from v$active_session_history
where sample_time between to_date('15022017 214500','ddmmyyyy hh24miss') and  to_date('15022017 215000','ddmmyyyy hh24miss')
and USER_ID in (select user_id from dba_users where username = '<your user name>')
order by session_id, SESSION_SERIAL#,SAMPLE_TIME;

以下是一个示例输出,模拟由表锁定阻止的INSERT

SAMPLE_TIME                 SESSION_ID SESSION_SERIAL# SQL_ID        TOP_LEVEL_SQL_ID SQL_OPNAME   PLSQL_ENTRY_OBJECT_ID EVENT                    BLOCKING_SESSION_STATUS BLOCKING_SESSION BLOCKING_SESSION_SERIAL#
--------------------------- ---------- --------------- ------------- ---------------- -----------  --------------------- -----------------------  ----------------------- ---------------- ------------------------
15.02.17 21:45:20,669000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:21,683000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:22,682000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:23,680000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:24,679000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:25,693000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:26,691000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 
15.02.17 21:45:27,689000000         11           10976 gr2assvfzr2v7 6j87w7zmmzpsk    INSERT                       154744 enq: TM - contention    VALID                                 13                     4283 

重要信息是时间戳,会话标识,SQL操作(您期望INSERT)和EVENT。 在我的示例中,您会看到EVENT enq: TM - contention表示表已锁定且会话无法执行插入操作。 当然,您可能会看到不同的事件 - 请检查Oracle documentation以解决问题原因。 最后,您会看到阻止状态阻止会话,它们可以提供解决方案出现问题的原因。

如果您没有在数据库中看到任何可疑证据(阻止或等待状态),请检查您的应用程序的日志。