1. 程式人生 > >Mysql中事務隔離級別與binlog_format的一點理解

Mysql中事務隔離級別與binlog_format的一點理解

    之前幾年的軟體開發,總是離不開Oracle,涉及的各大專案中使用的資料庫也大多為Oracle,偶爾遇到Mysql也是簡單的使用,一直覺得Mysql很小型也很簡單,對其的理解也處於皮毛階段,最近遇到了一些Mysql的問題,對其中的事務隔離級別,以及binlog_format方法,有了一些瞭解,這裡簡單的整理和總結一下。     首先回顧一下那傷心的往事:涉及支付介面和使用者資金,最初在支付介面回撥時,需要更新使用者以及資金的一些記錄,需要同時對多張表進行更新,最初的程式碼遺漏了對事務的控制,導致了資料庫偶爾出現表資料未更新的bug,但是在程式碼中增加完事務後,卻總是伴隨著這樣的異常資訊:
java.sql.SQLException: Binary logging not possible. Message: Transaction level'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'
    簡單翻譯一下:事務隔離級別為READ-COMMITTED的InnoDB引擎,在binlog方式為STATEMENT時並不安全。     開發框架使用的是開源的JFinal,最初總以為是JFinal的問題,於是立刻在伺服器上去除事務的控制程式碼,恢復最初版本的程式碼,開始解決問題,經過一段時間的百度和google,在這裡找到了答案
關於JFinal中的事務處理
,瞭解到了Mysql低版本存在的一個bug,官方的bug反饋:http://bugs.mysql.com/bug.php?id=40360。     造成問題的原因可能是由於InnoDB與binlog不相容導致,伺服器上的mysql版本也是5.1,於是乎,採用了最簡單的辦法來解決這個問題,資料庫升級,這裡感謝我的同事,花費了一些時間將資料庫版本升級到了最新的穩定版5.7,以為問題解決了,重新控制事務,在線上執行。     好吧,你猜到了,問題更嚴重了,所有的支付都出現了問題,這時出現的異常資訊是:
Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
    簡單翻譯一下:無法寫入二進位制檔案,因為BINLOG_FORMAT方式為STATEMENT,存在一個或多個表使用的儲存引擎是基於行的日誌記錄,InnoDB資料庫引擎, 當事務隔離級別為READ COMMITTED 或READ UNCOMMITTED 時,只限定於binlog為Row方式。     先來了解一下Mysql的資料庫儲存引擎,有很多中,不用常用的有以下兩種:MyISAM和InnoDB,兩者最主要的區別是:MyISAM是預設的錯處引擎,不支援事務,InnoDB支援事務。

暫無圖片

暫無圖片

    翻看JFinal的原始碼,在控制事務的時候預設的是READ_COMMITTED,資料庫在更新的時候,由於預設的binlog_format為STATEMENT,所以才導致了異常的出現,問題的根源是找到了,那麼應該怎麼解決呢?我們先來了解一下binlog:     BINLOG就是一個記錄SQL語句的過程,和普通的LOG一樣,它以二進位制儲存,普通的LOG以十進位制儲存,binlog有以下幾種方式:STATEMENT、ROW、MIXED,預設的日誌記錄方式,即binlog_format為STATEMENT,當資料庫儲存引擎為InnoDB時,在使用到事務控制,並且事務隔離級別為就READ COMMITTED 或
READ UNCOMMITTED時,就可能出現上面的異常,三種方式的不同區別,請參閱(MySQL binlog_format (Mixed,Statement,Row))。     最後得出的解決方案是,修改binlog_format,即設定為ROW或MIXED,最終將資料庫中的binlog設定為'MIXED',使用的依據是:

暫無圖片

    具體是否能夠解決當前的錯誤,還需要等待明天的測試,希望一切順利吧。同樣的對於binlog和事務隔離級別的測試,也可以參閱這裡:mysql binlog格式與事務級別read committed的關係     這裡具體的修改可以通過修改my.ini或 my.cnf檔案,也可以在sql命令模式下,使用:
#檢視事務隔離級別 select @@tx_isolation; #檢視binlog方式 select @@binlog_format; #設定session級別的BINLOG SET SESSION binlog_format = 'MIXED' ; #設定系統級別的binlog SET GLOBAL binlog_format = 'ROW';