起因

周六,7:10,闹钟还没响,客户电话过来了。

“彬哥,我们XX平台XX功能导致数据库死锁了,上次某某上去看过,把死锁的sqlserver进程杀过,但还是出现这个问题,麻烦你看一下”

“...”

起床,嗽口,吃个西红柿当早餐,出门(家里没网)

经过

连接服务器,重现问题

问题是:

某功能,点击之后等啊等,等啊等,等死了都没等到响应

所以

上次某某上去看过

使用这句sql查询到有被锁的连接
-- 查询死锁 select request_session_id spid,
OBJECT_NAME(resource_associated_entity_id) tableName from sys.dm_tran_locks
where resource_type='OBJECT'
于是将查询出来的死锁进程杀掉——但结果没用

凡是这种线程问题,都可以上jstack

找到java进程id,上jstack工具查看
D:\Program Files\Java\jdk1.8\bin>jstack 15316 > jstatck.log
将日志文件jstatck.log,拷贝到本地打开查看,
"http-nio-8080-exec-25" #197 daemon prio=5 os_prio=0 tid=0x0000000041b70800
nid=0x1530 waiting on condition [0x000000005f67f000] java.lang.Thread.State:
TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to
wait for <0x00000003c66f3d98> (a
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) at
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:85) at
org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:31) at
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
这种java库的线程不用看,看我们自己写的代码部分
"http-nio-8080-exec-19" #191 daemon prio=5 os_prio=0 tid=0x000000003d743800
nid=0xce0 runnable [0x000000005ee5b000] java.lang.Thread.State: RUNNABLE at
java.net.SocketInputStream.socketRead0(Native Method) at
java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at
java.net.SocketInputStream.read(SocketInputStream.java:171) at
java.net.SocketInputStream.read(SocketInputStream.java:141) at
org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
at
org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
at
org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
at
org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:140)
at
org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at
org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at
org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at
org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:153)
at
org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at
org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at
org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:254)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) at
org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) at
org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
at 我们公司的代码.RestHandler.httpExecute(RestHandler.java:50) at
我们公司的代码.RestHandler.operatorToXXZX(RestHandler.java:44) at
我们公司的代码.ShortTermForecastService.saveToCIMISS(ShortTermForecastService.java:334)
...(其它省略)
在这里找到了与我们公司的代码相关的内容。

这里表明两个问题:

1. 说明这个线程正在运行,与上述“等啊等,等啊等”的现象描述是一致的(没有运行完的线程不就这样么)

2. 这里的代码在访问某个url,并且一直在等待对方的响应

找到了出问题的地方,就可以查看源代码分析了
private void saveToCIMISS(final Long fid) throws Exception { //... 省略上面代码
RestHandler.operatorToXXZX(EnumXXZX.INS_SHORTTREMPRODUCT.getUrl(),
EnumXXZX.INS_SHORTTREMPRODUCT.getInterfaceId(), param); //...省略下面代码 }
然后看看是调用了哪个 url 导致,至此问题原因已找到!

结果及分析

为什么会有“死锁”sqlserver连接呢

其实这并不是什么“死锁”,只是正常的锁

上面这个线程执行过程,会使用事务,事务引进的锁——而因为在事务过程中产生了外部的http访问,且该http长时间没有响应,导致事务锁因此也长时间占用数据库。

所以,表面看起来是数据库“死锁”了

解决问题思路

凡是线程问题,都可以用jstack工具

其它

面试的时候,面试官问我

“你遇到过最难解决的问题,你是怎么解决的?”

“我特么都是问题解决了就忘记了,所以没啥印象”

不过,我是在心里说的

所以,对于别人问我的问题,我决定记录下来,免得将来忘记了

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信