浅析MySQL JDBC连接配置上的两个误区
相信使用MySQL的同學(xué)都配置過它的JDBC驅(qū)動,多數(shù)人會直接從哪里貼一段URL過來,然后稍作修改就上去了,對應(yīng)的連接池配置也是一樣的,很少有人會去細想這每一個參數(shù)都是什么含義。今天我們就來聊兩個比較常見的配置——是否要開啟autoReconnect和是否緩存PreparedStatement。
\\一、autoReconnect=true真的好用么?
\\筆者看到過很多MySQL的URL里都是這樣寫的,復(fù)制過來改改IP、端口和庫名就能用了:
\\jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?autoReconnect=true\u0026amp;...\\從字面上看挺好的,在連接斷開后還會自動重連,加之MySQL有8小時自動斷開連接的特性,在斷開后連接會重連,多好的功能呀。但是如果你去閱讀一下MySQL Connect/J開發(fā)手冊的相關(guān)章節(jié),就會看到官方是這么說明的:
\\\The use of this feature is not recommended, because it has side effects related to session state and data consistency when applications don't handle SQLExceptions properly, and is only designed to be used when you are unable to configure your application to handle SQLExceptions resulting from dead and stale connections properly.
\\\簡單來說,不推薦開啟這個特性,因為有副作用,在沒有正確處理SQLException時容易造成會話狀態(tài)和數(shù)據(jù)一致性的問題。
\\一般的應(yīng)用都會使用數(shù)據(jù)庫連接池,那我們的連接池是否正確地處理了拋出的SQLException呢?抱著這個疑問,我們來看看阿里的Druid連接池是怎么處理的。
\\首先,通過設(shè)置合理的健康檢查及連接存活時間能解決大部分問題;其次,它有針對特定異常的處理邏輯,在MySqlExceptionSorter中會對特定返回碼、異常類(比如com.mysql.jdbc.CommunicationsException和com.mysql.jdbc.exceptions.jdbc4.CommunicationsException)以及錯誤消息進行處理,如果是致命錯誤就把連接拋棄。也就是說,如果用了Druid,不管是否設(shè)置了autoReconnect,都能保證后續(xù)請求的正確處理。JBoss的連接池實現(xiàn)也有類似的特性。
\\二、MySQL是否真的不用打開PSCache?
\\一般在設(shè)置連接池時,都會有類似下面的設(shè)置:
\\\u0026lt;property name=\"poolPreparedStatements\" value=\"true\" /\u0026gt;\\u0026lt;property name=\"maxPoolPreparedStatementPerConnectionSize\" value=\"20\" /\u0026gt;\\很多文章上都說PSCache對使用游標的數(shù)據(jù)庫有巨大的性能提升,但MySQL不建議開啟,因為它不支持游標。所以很多人在用MySQL時,都會將poolPreparedStatements設(shè)置為false,就連Druid的文檔上也是這么寫的。
\\但事實真的是這樣么,MySQL使用PSCache真的對性能沒有提升么?
\\先來看看關(guān)于游標的問題,其實大部分文章的表述不太準確,現(xiàn)在的MySQL在存儲過程里是支持游標的,但其他地方的確不支持,具體詳見官方手冊(MySQL supports cursors inside stored programs.)。但這并不是我們要討論的關(guān)鍵。
\\3.1.0版本后的JDBC驅(qū)動里有一個參數(shù)是useServerPrepStmts,如果服務(wù)器支持的話,會開啟服務(wù)端PreparedStatement,默認是false。官方手冊中有如下說明:
\\\Server-side Prepared Statements - Connector/J 3.1 will automatically detect and use server-side prepared statements when they are available (MySQL server version 4.1.0 and newer).
\\\也就是說在MySQL 4.1.0版本后,3.1.0以上的驅(qū)動會檢測到支持服務(wù)端PreparedStatement,并且啟用該特性。根據(jù)MySQLTUTORIAL上的說明,整個過程分為PREPARE、EXECUTE和DEALLOCATE PREPARE三步。MySQL JDBC驅(qū)動的Contributor Jess Balint在StackOverflow上做了一個詳細的說明,《High-Performance Java Persistence》的作者也專門撰寫文章分析了兩者的區(qū)別。
\\\ps=conn.prepareStatement(\"select ?\")\ps.setInt(1, 42)\ps.executeQuery()\ps.setInt(1, 43)\ps.executeQuery()\\\上述代碼在使用客戶端PreparedStatement時,MySQL日志里看到的是:
\\255 Query select 42\255 Query select 43\\如果用的是服務(wù)端PreparedStatement,看到的則是(實際每次執(zhí)行只會傳占位符的值,語句是不傳的):
\\\254 Prepare select ?\254 Execute select 42\254 Execute select 43\\\在整個使用過程中,Prepare只會做一次,在這時服務(wù)端會對語句進行解析,后續(xù)收到具體值時會優(yōu)化執(zhí)行計劃。如果同一條語句每次都新建PreparedStatement,那么每次都會多一回網(wǎng)絡(luò)交互和語句解析,這顯然是可以優(yōu)化的。
\\綜上所述,現(xiàn)在在使用MySQL時(如果版本比較新的話),出于性能考慮,應(yīng)該在數(shù)據(jù)庫連接池上開啟針對PreparedStatement的緩存。如果沒有使用連接池,或者所用的連接池不支持PSCache,也可以在JDBC連接上設(shè)置cachePrepStmts=true。
\\事實上,MySQL的JDBC驅(qū)動還有不少針對性能的優(yōu)化,比如設(shè)置useConfigs=maxPerformance(請酌情使用),相當于同時做了如下設(shè)置:
\\\cachePrepStmts=true\cacheCallableStmts=true\cacheServerConfiguration=true\useLocalSessionState=true\elideSetAutoCommits=true\alwaysSendSetIsolation=false\enableQueryTimeouts=false\\\各位同學(xué),是時候檢視一下自己的系統(tǒng)是如何連接MySQL的了,時代在發(fā)展,有些以前適用的配置也許就不再合適了。
總結(jié)
以上是生活随笔為你收集整理的浅析MySQL JDBC连接配置上的两个误区的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux文件查找之findlocate
- 下一篇: 基于mysql的主从复制之Mycat简单