週六,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工具
面試的時候,面試官問我
「你遇到過最難解決的問題,你是怎麼解決的?」
「我特麼都是問題解決了就忘記了,因此沒啥印象」
不過,我是在內心說的
因此,對於別人問個人問題,我決定記錄下來,省得未來忘記了