Wir haben eine Multi-threaded Java-Anwendung mit einer Web-UI und REST-API, die mit Java 6 kompiliert und in Tomcat 6 ausgeführt wird. Während Operationen verwendet OJDBC auf seine Oracle DB zugreifen Millionen Mal am Tag. Alle zwei oder drei Monate hängt eine der DB-Abfragen und wird nie zurückgegeben, wodurch ein Teil der Anwendung die Verarbeitung beendet und ein Rückstand erstellt wird. Andere Threads können mit der DB kommunizieren und ihre Arbeit erledigen, nur ein Thread wird gehängt, was leider die Dateiverarbeitung stoppt.Java OJDBC Oracle SQL-Abfrage hängt alle paar Monate einmal
Ein Thread-Dump zeigt, dass der Faden aus der Steckdose wird das Auslesen der nie mal noch geschlossen wird:
"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)
Wenn dies die DBAs geschieht auf dem DB-Server ausgesehen hat und keine lange Lauf Abfrage sehen . Die Lösung ist Tomcat zu recyceln, was das Problem behebt, aber ich möchte herausfinden, ob es einen programmatischen Weg gibt, um damit umzugehen. Ich habe Anhänge gesehen, die sich auf ähnliche Probleme beziehen, die behoben werden, indem die LINUX-Box, auf der der DB-Server läuft, recycelt wird, aber das ist für uns keine Option; Ich brauche eine Korrektur auf Anwendungsebene.
Die DB Ressource verwendet definiert:
<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 Treiber verwendet wird, ist: ojdbc6_g-11.2.0.4.0.jar
Die DB-Version ist: 11.2.0.3.0
der Java-Code die Abfrage ausgeführt wird:
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();
Dies ist die Quelle für getConnection():
"ds" ist definiert als: private statische DataSource ds = null; und wird unter Verwendung initialisiert:
Context initContext = new InitialContext();
ds = (DataSource)initContext.lookup(wrapper.getCSADBJNDIName());
Ich bin damit einverstanden @unleashed, mögliche Netzfehler, könnte aber auch langsame Client-Seite Verarbeitung oder auch eine zu geringe sein Array-Fetch-Größe, die zu viele Netzwerk-Roundtrips verursachen würde ["SQL * Net ist ein gesprächiges Protokoll"]. In diesem Fall wird durch das Prellen des App-Servers die anstößige Leerlaufsitzung beendet, die den Engpass darstellt. –
Vielen Dank sowohl für die Antworten und die Referenzen, sehr nützlich.Der Netzwerkfehler erscheint in diesem Fall viel plausibler. Wie der obige Code zeigt, wird Tomcat-DB-Ressource verwendet. Gibt es eine Möglichkeit, ein Timeout in Tomcat zu definieren, anstatt den DriverManager zu verwenden? – user3722575