我们经常看到Oracle(11gR2)在尝试通过JDBC进行更新时挂起。访问Oracle的线程是应用程序中连接到数据库的唯一线程,它永远等待Oracle返回数据。可能另一个进程可能访问了同一个数据库并更新了一个表,但我认为Oracle会自动检测死锁并返回错误。在我们的例子中,数据库只是挂起。有什么可能导致这个或通过一些DBA命令调试的方法的想法?这是我遇到的堆栈跟踪:
Thread 7315: (state = IN_NATIVE)
- java.net.SocketInputStream.socketRead0(java.io.FileDescriptor, byte[], int, int, int) @bci=0 (Compiled frame; information may be imprecise)
- java.net.SocketInputStream.read(byte[], int, int, int) @bci=79 (Compiled frame)
- java.net.SocketInputStream.read(byte[], int, int) @bci=11 (Compiled frame)
- oracle.net.ns.Packet.receive() @bci=180, line=308 (Compiled frame)
- oracle.net.ns.DataPacket.receive() @bci=1, line=106 (Compiled frame)
- oracle.net.ns.NetInputStream.getNextPacket() @bci=48, line=324 (Compiled frame)
- oracle.net.ns.NetInputStream.read(byte[], int, int) @bci=33, line=268 (Compiled frame)
- oracle.net.ns.NetInputStream.read(byte[]) @bci=5, line=190 (Compiled frame)
- oracle.net.ns.NetInputStream.read() @bci=73, line=107 (Compiled frame)
- oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket() @bci=94, line=143 (Compiled frame)
- oracle.jdbc.driver.T4CSocketInputStreamWrapper.read() @bci=18, line=80 (Compiled frame)
- oracle.jdbc.driver.T4CMAREngine.unmarshalUB1() @bci=6, line=1137 (Compiled frame)
- oracle.jdbc.driver.T4CTTIfun.receive() @bci=11, line=350 (Compiled frame)
- oracle.jdbc.driver.T4CTTIfun.doRPC() @bci=63, line=227 (Compiled frame)
- oracle.jdbc.driver.T4C8Oall.doOALL(boolean, boolean, boolean, boolean, boolean, oracle.jdbc.internal.OracleStatement$SqlKind, int, byte[], int, oracle.jdbc.driver.Accessor[], int, oracle.jdbc.driver.Accessor[], int, byte[], char[], short[], int, oracle.jdbc.driver.DBConversion, byte[], java.io.InputStream[][], byte[][][], oracle.jdbc.oracore.OracleTypeADT[][], oracle.jdbc.driver.OracleStatement, byte[], char[], short[], oracle.jdbc.driver.T4CTTIoac[], int[], int[], int[], oracle.jdbc.driver.NTFDCNRegistration) @bci=769, line=531 (Compiled frame)
- oracle.jdbc.driver.T4CPreparedStatement.doOall8(boolean, boolean, boolean, boolean, boolean) @bci=749, line=208 (Compiled frame)
- oracle.jdbc.driver.T4CPreparedStatement.executeForRows(boolean) @bci=226, line=1046 (Compiled frame)
- oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout() @bci=301, line=1336 (Compiled frame)
- oracle.jdbc.driver.OraclePreparedStatement.executeInternal() @bci=119, line=3613 (Compiled frame)
- oracle.jdbc.driver.OraclePreparedStatement.executeUpdate() @bci=13, line=3694 (Compiled frame)
- oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate() @bci=4, line=1354 (Compiled frame)
- sun.reflect.GeneratedMethodAccessor16.invoke(java.lang.Object, java.lang.Object[]) @bci=40 (Compiled frame)
- sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) @bci=6 (Compiled frame)
- java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) @bci=57 (Compiled frame)
- oracle.ucp.jdbc.proxy.StatementProxyFactory.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) @bci=513, line=294 (Compiled frame)
- oracle.ucp.jdbc.proxy.PreparedStatementProxyFactory.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) @bci=122, line=137 (Compiled frame)
- com.sun.proxy.$Proxy3.executeUpdate() @bci=9 (Compiled frame)
答案 0 :(得分:6)
当会话1持有会话2正在等待的锁定而会话2同时持有会话1正在等待的锁定时,会发生死锁。听起来你正在描述的是一个简单的阻塞锁定,其中会话1(你的应用程序)被阻塞等待会话2(某些其他应用程序)持有的锁定,该锁定还没有结束其事务。在这种情况下,会话1将无限期地阻止在会话2上等待。
如果你想从后端看一下,gv$session
将为数据库中打开的每个会话都有一行。由于您的应用程序只有一个访问数据库的线程,我猜想osuser
,process
,machine
,terminal
和program
的某种组合会允许您识别与您的应用程序关联的会话。完成后,请查看blocking_instance
和blocking_session
列。如果填充了这些,则会阻止您的会话等待其他会话提交或回滚。您可以使用该会话的v$session
行来尝试找出哪个应用程序错误地持有锁定的时间过长。
"经典"这里的问题往往是跨越用户交互锁定行的应用程序。例如,如果我编写一个执行悲观锁定的应用程序,当我将其呈现给用户时我会锁定一行并等待用户在释放锁之前修改该行。但问题是,如果用户在没有做任何其他事情的情况下去吃午餐(或者应用程序崩溃),该行将无限期地锁定在数据库中,直到DBA出现并杀死持有该数据库的会话。锁。
答案 1 :(得分:2)
查看v $ active_session_history,其中显示了会话等待的最后等待事件。