發(fā)現(xiàn)問題
在一次撈取Top SQL中,發(fā)現(xiàn)DB大量執(zhí)行 select @@session.tx_read_only
,幾乎每一條DML語句前,都會有這么一個sql。但是應用層并沒有做特殊處理,那么這個SQL語句有什么作用?是誰執(zhí)行了它?
詳細介紹
此sql的作用主要是判斷事務是否為只讀事務。MySQL自身會對只讀事務做優(yōu)化,這是 MySQL5.6.5 版本 以后才出現(xiàn)的。 http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_tx_read_only
定位到MySQL的驅動包
ConnectionImpl.java :
可以看到,在if條件中,對MySQL的 版本 做了判斷,同時也有 !getUseLocalSessionState()
這么一個條件,對應 JDBC參數(shù)useLocalSessionState ,當這個值為false時,會發(fā)出select @@session.tx_read_only
; 這條sql。
默認情況下,我們的連接串信息沒有包含useLocalSessionState參數(shù)的設置,這個值默認為false。
這個值的作用是驅動程序是否使用autocommit,read_only和transaction isolation的內部值(jdbc端的本地值)。
如果設置為false,則需要這個判斷這三個參數(shù)的場景,都需要發(fā)語句到遠端請求,比如更新語句前,
需要發(fā)語句select @@session.tx_read_only
確認會話是否只讀。
如果設置為true,則只需要取本地值即可。這可以解釋為什么有的實例 select @@session.tx_read_only
語句很多。
一般情況下,驅動可以保證本地值與遠程服務器值保持一致。當應用調用setAutoCommit, setTransactionIsolation 和 setReadOnly這三個接口設置參數(shù)值時,會與遠程服務器同步。
具體而言,
當useLocalSessionState為true時,若值與本地值不一致,則發(fā)往遠程更新;
當useLocalSessionState為false時,無論設置值與本地值是否一致,每次都發(fā)往遠程更新。這可以解釋為什么有些實例set autocommit語句比較多。
但是,若用戶設置參數(shù)時不通過JDBC接口(比如setAutoCommit),而是執(zhí)行語句'set autocommit=xxx'
設置, 那么就會存在本地值與遠程不一致的情況,進而可能導致修改參數(shù)useLocalSessionState后,業(yè)務邏輯發(fā)生變化。
相關設置的SQL語句:
set autocommit=0 /*設置會話自動提交模式*/ 對應的JDBC接口: setAutoCommit(false)
set tx_isolation='read-committed' /*設置事務的隔離級別*/ 對應的JDBC接口:setTransactionIsolation('read-committed')
set tx_read_only=0; /*設置只讀事務*/ 對應的JDBC接口:setReadOnly(false)
設置useLocalSessionState默認值為ture,可能導致業(yè)務邏輯含義發(fā)生變化。觸發(fā)的條件是,用戶通過SQL語句直接設置自動提交參數(shù),隔離級別參數(shù)或只讀事務參數(shù)。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。