周六,7:10,闹钟还没响,客户电话过来了。java
“彬哥,咱们XX平台XX功能致使数据库死锁了,上次某某上去看过,把死锁的sqlserver进程杀过,但仍是出现这个问题,麻烦你看一下”面试
“...”sql
起床,嗽口,吃个西红柿当早餐,出门(家里没网)数据库
链接服务器,重现问题apache
问题是:tomcat
某功能,点击以后等啊等,等啊等,等死了都没等到响应服务器
因此session
上次某某上去看过app
使用这句sql查询到有被锁的链接socket
-- 查询死锁 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工具
面试的时候,面试官问我
“你遇到过最难解决的问题,你是怎么解决的?”
“我特么都是问题解决了就忘记了,因此没啥印象”
不过,我是在内心说的
因此,对于别人问个人问题,我决定记录下来,省得未来忘记了