问题描述 在通过由应用程序或 WebLogic Server 本身使用的 JDBC 连接进行调用时,此连接会在整个调用期间内阻塞一个 WebLogic Server 执行线程。尽管在 SQL 查询上阻塞的线程需要等待,但 JVM 将通过其线程调度机制确保 CPU 获得可运行线程。但是,由 JDBC 调用占用的线程将保留给应用程序使用,直至该调用从 SQL 查询返回。
即使事务超时也不会终止由在此事务中登记的资源完成的任何操作,或者使其超时。这些操作将正常地运行,而不会出现中断。事务超时只是在事务上设置一个标记,将其标记为回滚,这样提交此事务的任何后续请求都将失败,系统抛出 TimedOutException 或 RollbackException。但是,如前所述,长时间运行的 JDBC 调用会导致 WebLogic Server 执行线程阻塞,如果所有线程均被阻塞,没有能够处理传入请求执行线程,则最终可导致实例挂起。
最新版本的 WebLogic Server 具有健全性检查功能,能够定期检查线程不响应的时间是否达到特定时长(缺省值为 600 秒)。如果是这样,系统会向日志文件输出一条如下的错误消息:
####<Nov 6, 2004 1:42:30 PM EST> <Warning> <WebLogicServer> <mydomain> <myserver> <CoreHealthMonitor> <kernel identity> <> <000337> <ExecuteThread: '64' for queue: 'default' has been busy for "740" seconds working on the request "Scheduled Trigger", which is more than the configured time (StuckThreadMaxTime) of "600" seconds.>
这并不会中断线程,而只是提供给管理员的一项通知。阻塞线程恢复为正常状态的唯一途径是等待它正处理的请求完成。这种情况下,WebLogic Server 日志文件中将出现一条如下的消息:
####<Nov 7, 2004 4:17:34 PM EST> <Info> <WebLogicServer><mydomain> <myserver> <ExecuteThread: '66' for queue: 'default'> <kernel identity> <> <000339> <ExecuteThread: '66' for queue: 'default' has become "unstuck".>
"ExecuteThread-39" daemon prio=5 tid=0x401660 nid=0x33 waiting for monitor entry [0xd247f000..0xd247fc68] at java.sql.DriverManager.getConnection(DriverManager.java:188) at com.bla.updateDataInDatabase(MyClass.java:296) at javax.servlet.http.HttpServlet.service(HttpServlet.java:865) at weblogic.servlet.internal.ServletStubImpl.invokeServlet (ServletStubImpl.java:120) at weblogic.servlet.internal.ServletContextImpl.invokeServlet (ServletContextImpl.java:945) at weblogic.servlet.internal.ServletContextImpl.invokeServlet (ServletContextImpl.java:909) at weblogic.servlet.internal.ServletContextManager.invokeServlet (ServletContextManager.java:269) at weblogic.socket.MuxableSocketHTTP.invokeServlet (MuxableSocketHTTP.java:392) at weblogic.socket.MuxableSocketHTTP.execute(MuxableSocketHTTP.java:274) at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:130)
挂起的数据库 对于依赖于数据库的应用程序来说,良好的数据库性能是其性能的关键。因此,挂起的数据库可能会阻塞 WebLogic Server 实例中许多或所有可用的执行线程并最终导致服务器挂起。要诊断这一问题,应从挂起的 WebLogic Server 实例获得 5 到 10 个 Thread Dump,并检查您的执行线程(在缺省队列或您的应用程序线程队列中)当前是否在 SQL 调用之中并在等待来自数据库的结果。当前发出 SQL 查询的线程的典型堆栈跟踪如下例所示:
"ExecuteThread: '4' for queue: 'weblogic.kernel.Default'" daemon prio=5 tid=0x8e93c8 nid=0x19 runnable [e137f000..e13819bc] at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at oracle.net.ns.Packet.receive(Unknown Source) at oracle.net.ns.DataPacket.receive(Unknown Source) at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source) at oracle.net.ns.NetInputStream.read(Unknown Source) at oracle.net.ns.NetInputStream.read(Unknown Source) at oracle.net.ns.NetInputStream.read(Unknown Source) at oracle.jdbc.ttc7.MAREngine.unmarshalUB1(MAREngine.java:931) at oracle.jdbc.ttc7.MAREngine.unmarshalSB1(MAREngine.java:893) at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:375) at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1983) at oracle.jdbc.ttc7.TTC7Protocol.fetch(TTC7Protocol.java:1250) - locked <e8c68f00> (a oracle.jdbc.ttc7.TTC7Protocol) at oracle.jdbc.driver.OracleStatement.doExecuteQuery(OracleStatement.java:2529) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2857) at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate (OraclePreparedStatement.java:608) - locked <e5cc44d0> (a oracle.jdbc.driver.OraclePreparedStatement) - locked <e8c544c8> (a oracle.jdbc.driver.OracleConnection) at oracle.jdbc.driver.OraclePreparedStatement.executeQuery (OraclePreparedStatement.java:536) - locked <e5cc44d0> (a oracle.jdbc.driver.OraclePreparedStatement) - locked <e8c544c8> (a oracle.jdbc.driver.OracleConnection) at weblogic.jdbc.wrapper.PreparedStatement.executeQuery(PreparedStatement.java:80) at myPackage.query.getAnalysis(MyClass.java:94) at jsp_servlet._jsp._jspService(__jspService.java:242) at weblogic.servlet.jsp.JspBase.service(JspBase.java:33) at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run (ServletStubImpl.java:971) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:402) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:305) at weblogic.servlet.internal.RequestDispatcherImpl.includ e(RequestDispatcherImpl.java:607) at weblogic.servlet.internal.RequestDispatcherImpl.include (RequestDispatcherImpl.java:400) at weblogic.servlet.jsp.PageContextImpl.include(PageContextImpl.java:154) at jsp_servlet._jsp.__mf1924jq._jspService(__mf1924jq.java:563) at weblogic.servlet.jsp.JspBase.service(JspBase.java:33) at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run (ServletStubImpl.java:971) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:402) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:305) at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run (WebAppServletContext.java:6350) at weblogic.security.acl.internal.AuthenticatedSubject.doAs (AuthenticatedSubject.java:317) at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:118) at weblogic.servlet.internal.WebAppServletContext.invokeServlet (WebAppServletContext.java:3635) at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2585) at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:197) at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:170)
java.sql.SQLException: ORA-00060: deadlock detected while waiting for resource at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:170) at oracle.jdbc.oci8.OCIDBAccess.check_error(OCIDBAccess.java:1614) at oracle.jdbc.oci8.OCIDBAccess.executeFetch(OCIDBAccess.java:1225) at oracle.jdbc.oci8.OCIDBAccess.parseExecuteFetch(OCIDBAccess.java:1338) at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:1722) at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:1647) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout (OracleStatement.java:2167) at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate (OraclePreparedStatement.java:404)
池收缩 数据库的物理连接是应当打开一次并尽可能长时间保持打开的资源,因为新的连接请求对于数据库、操作系统内核及 WebLogic Server 而言是一个相当大的资源开销。因此,应在生产系统中禁用池收缩,使这一开销保持最小程度。如果启用池收缩,一旦对该池发出的连接请求不能得到满足,空闲的池连接就将被关闭,然后重新打开。