簡體   English   中英

Java OJDBC Oracle SQL查詢每幾個月掛起一次

[英]Java OJDBC Oracle SQL query hangs once every few months

我們有一個帶有Web UI和REST API的多線程Java應用程序,該應用程序是使用Java 6編譯並在tomcat 6中運行的。在操作過程中,它每天使用OJDBC來訪問其Oracle DB數百萬次。 每兩個或三個月一次,一個數據庫查詢掛起並且永不返回,這將導致部分應用程序停止處理並積壓待辦事項。 其他線程能夠與數據庫通信並完成其工作,只有一個線程掛起,不幸的是這停止了文件處理。

線程轉儲顯示線程正在從永遠不會超時也不會被關閉的套接字讀取:

"FileUpload" daemon prio=10 tid=0x00002b8e60617800 nid=0xf9e runnable [0x00002b8e5e10b000]
java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at oracle.net.ns.Packet.receive(Packet.java:311)
    at oracle.net.ns.DataPacket.receive(DataPacket.java:103)
    at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:312)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:257)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:182)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:99)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:121)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:77)
    at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1173)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:309)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:200)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:543)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:238)
    at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:1244)
    at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1492)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1710)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:4372)
    at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:4453)
- locked <0x00002b8e1c2d7010> (a oracle.jdbc.driver.T4CConnection)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:6270)
    at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
    at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
    at xxx.OracleFileInfoDAO.getFilesToUpload(OracleFileInfoDAO.java:874)

發生這種情況時,DBA已經查看了數據庫服務器,但看不到長時間運行的查詢。 解決方案是回收tomcat,這可以解決問題,但我想了解是否有編程的方式來處理此問題。 我已經看到附錄中提到了類似的問題,這些問題可以通過回收運行數據庫服務器的LINUX盒來解決,但這對我們來說不是一個選擇。 我需要在應用程序級別進行修復。

使用以下方法定義數據庫資源:

<Resource auth="Container" description="Oracle Datasource" name="xxx" scope="shareable" type="javax.sql.DataSource" url="jdbc:oracle:thin:@xxx:1521/xxx"  driverClassName="oracle.jdbc.driver.OracleDriver" username="xxx" password="xxx" maxWait="5000" maxActive="100" maxIdle="20" removeAbandoned="true" testOnReturn="true" testOnBorrow="true" validationQuery="select 1 from dual" />   

使用的OJDBC驅動程序是:ojdbc6_g-11.2.0.4.0.jar

DB版本是:11.2.0.3.0

執行查詢的Java代碼為:

                con = CSAConnectionManager.getConnection();                     
            StringBuilder strBuf = new StringBuilder(SQL_SELECT_FILE_INFO_TO_UPLOAD);
            ps = con.prepareStatement(strBuf.toString());
            ps.setString( 1, hostname );
            ps.setString( 2, containerId );
            ps.setMaxRows( maxRows );

            Date before = new Date();
            ResultSet rs = ps.executeQuery();

這是getConnection()的來源:

    public static Connection getConnection() throws Exception
{
    return instance.getInstanceConnection();
}

public Connection getInstanceConnection() throws Exception
{
    Connection con = null;
    if(ds != null)
    {
        con = ds.getConnection();
    }
    else
    {
        String dburl = wrapper.getDBUrl();
        String username = wrapper.getDBUserName();
        String password = wrapper.getDBPassword();      
        String driverClass = wrapper.getDBDriverClass();
        Class.forName(driverClass).newInstance();

        con = DriverManager.getConnection(dburl,username,password);
    }       
    con.setAutoCommit(false);
    return con;
}

“ ds”定義為:私有靜態數據源ds = null; 並使用初始化:

        Context initContext = new InitialContext();
        ds = (DataSource)initContext.lookup(wrapper.getCSADBJNDIName());

以我的經驗,這通常是網絡錯誤。 您的查詢已完成,但是您的客戶端仍在阻止它永遠不會收到的網絡響應。 這就是為什么啟動應用程序服務器會在重置應用程序服務器中的所有內容時起作用,但是啟動數據庫服務器卻沒有意義,因為它不是數據庫問題。 看看這個網站上的這個問題/答案...

有關網絡超時的問題

檢查會話是否為:

  1. 不活動-如果不活動,等待狀態是什么,它可能正在等待客戶端或網絡。
  2. 有任何涉及空閑會話的阻塞鎖(例如,它對未提交的事務持有一些鎖)。

還要檢查連接風暴(即,過多的會話訪問實例可能會導致嚴重的CPU問題)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM