前陣子碰到一個好玩的問題。
狀況:透過 hibernate + proxool + jtds 使用 SSO 方式連 SQL Server 時好時壞。常常出現 SQL Error: 0, SQLState: 08S01 無法連線狀況。
一聽到此狀況,就先給了建議,改採用 MS 之 JDBC Driver 試試。
後來回報是改採用 MS 的 Driver 情況反而更慘。錯誤就是都無法連線。
所以依此測試結果判斷,就去查看 source code。
結果發現在使用 hibernate 的 session 等處理都是透過 static 變數。
這樣當然會有問題,因 multi-thread 環境下,可能某 thread 已經關閉 session。另一個 thread 還在使用,就會發生問題。
因此請同事考慮 multi-thread 之情況,調整到好。
調整到好之後,問題依舊。
因此再建議改用最陽春的解法,直接透過 JDBC 而不透過 hibernate。
沒想到問題更嚴重了。
但同事後來又試了將 hibernate 由 3.2 換到 3.6 之後,竟然發現ok了。
所以歸咎於是 hibernate 的問題,但此結論實在不能說服我。
且此專案已經近尾聲,更換此 jar 檔等於整個專案都需要重測。
於是,就直接去客戶端實地查看問題。
再測試一遍,發現,hibernate 是有透過 proxool 連 DB,雖然有時會錯,但有連上後,因 Connection Pool 會保留此連線,因此後續就正常。
所以純 JDBC 版本也透過 proxool 來連,情況也與使用 hibernate 情況一致。
但只要換成新版 hibernate,就都正常。
心裡在想,會不會 hibernate 有自己重試連不上就重連機制啊。否則這實在無法解釋。
於是下載了 hibernate source code 來追。不論怎麼追就是無此機制。
但只要無法解釋,心理就會覺得不踏實,因此多試了幾次。
發現,透過新版 hibernate 還是會時好時壞,只是壞的機率低很多。
那就有可能了,可能新版 hibernate 做了最佳化,讓問題出現的機率低很多。
但這不代表問題解決了。
由於只要透過 SQL 認證來連就都不會出錯,改用 Windows SSO 認證才會。
且都是一開始連線就會出錯,還是感覺換成 MS JDBC Driver 應該會比較好。
都是 MS 的產品,應該穩很多吧。
果然換回舊版 hibernate,使用純 JDBC 模式連線,就算不用 Proxool 也非常穩定。
那之前說使用 MS JDBC 不行又是什麼一回事。
原來當時是使用 hibernate 的模式。
再換成 hibernate 模式後果然出錯。出現:
Caused by: java.lang.SecurityException: class "com.microsoft.sqlserver.jdbc.ISQLServerConnection$$FastClassByProxool$$2b8cf6af"'s signer information does not match signer information of other classes in the same package
看到此錯誤,其實就很明顯了。
這是因為 MS 之 JDBC Driver 的 JAR 檔有 sign 過。但卻不符合。
而此是透過 Proxool 才會有此錯誤。
當時建議兩個方案,改採 hibernate 本身陽春之 Connection Pool,或根本不要使用 Connection Pool。果然一換就可正常運作。
另一個方案就是把 MS JDBC Jar 檔內之 sign information 檔刪除。
最後 PM 決定不要動 JAR 檔,因此改採 hibernate 本身之 Connection Pool 來解決。
而在事後,我自己測試時,即將 MS JDBC Jar 檔內之 sign info 檔刪除。
確實透過 Proxool 也可正常連線。
至於為何 proxool 會有此問題呢? 追究其 exception dump,發現其是透過 cglib 去動態 load 物件。所以推測此為 Java 本身的限制,若是動態去 load 物件。而其物件之 Jar 檔是有 sign 過的。則必須驗證其正確性。
那為何當初換 MS JDBC Driver 時出錯沒有找出此問題呢?
因為當時 catch 到 exception 時,輸出到 Logging 沒有輸出 exception stack。
都只看到一行連線錯誤的訊息。錯失提早解決問題的時機。
總結:
- 使用 jtds 用 windows 認證 SSO 登入方式連 SQL Server 2005 會時好時壞。連 SQL Server 2008 則很穩定。此結論為推測,因未排除只連 SQL Server 2000 會不會正常。此案子是同時有連 2005 與 2008。但連 2008 都很正常。因此才做此推測。
- MS JDBC JAR 為何 signer 無法 match 還沒研究。
- 使用 Proxool 連 MS JDBC,須將 JAR 檔內之 sign info 檔案刪除。
- 不該疏忽任何 exception stack 輸出。
- 對無法解釋的行為,不能妄下結論。