mySQL 事物提交成功不等于数据保存成功
??????最近遇到過生產上的數據丟失問題,看到大家各種分析代碼,然后我發現很多人認為事物提交了就認為數據不會丟失!!!。。。我只能說這是公司沒有DBA,或者說大家不能深層次理解mySQL原理的悲哀!
????? ? 針對此,特意寫了這篇博客!(理解不深刻不準確之處,敬請指出)
現象
? ? ??正常情況下,我們會將一系列增,刪,改操作寫在一個事物中,也就是一個原子操作,那么理論上這一系列的操作,要么會同時成功,要么會同時失敗(回滾)!
????但實際上呢,數據庫返回失敗,那么這一系列數據庫操作肯定都不會成功,但如果數據庫返回成功,那么絕大部分情況都會會全部成功,但也有可能會部分成功,或者全部不成功。這也就是數據丟失。
mysql的數據丟失大致可以分為:
存儲引擎層面丟失數據 ??
????????在實際項目中,我們一般接觸到的是支持事物的InnoDB存儲引擎,此處只講innoDB存儲引擎的數據丟失。
????????InnoDB默認開啟內部的XA事物(實現方式是基于redo log和undo log),也就是采用日志先行的策略。在未開啟binlog的情況下,數據變更(數據的增,刪,改操作)會在內存中操作,并將事物順序寫入到redo log中,這時就會認為事物已經完成,響應事物提交成功。然后在一定條件下,才將內存中的數據合并到磁盤中。
??????所以,在持久化到磁盤的過程中,如果服務器宕機等導致內存中的數據丟失,數據也就會丟失。不過這種數據丟失是可以通過 recovery 重做日志,找回數據的。
? ? ? 這就是前面描述的數據丟失,根本原因就是內存中的數據沒有及時刷新到磁盤中。?所以InnoDB有一個特別的參數用于設置這兩個緩存的刷新: innodb_flush_log_at_trx_commit.
? ? ? 默認,innodb_flush_log_at_trx_commit=1,表示在每次事務提交的時候,都把log buffer刷到文件系統中去,并且調用文件系統的“flush”操作將緩存刷新到磁盤上去。這樣的話,數據庫對IO的要求就非常高了,如果底層的硬件提供的IOPS比較差,那么MySQL數據庫的并發很快就會由于硬件IO的問題而無法提升。
? ? ? 為了提高效率,保證并發,犧牲一定的數據一致性。innodb_flush_log_at_trx_commit 還可以設置為0和2。
? ? ? innodb_flush_log_at_trx_commit=0時,每隔一秒把log buffer刷到文件系統中去,并且調用文件系統的“flush”操作將緩存刷新到磁盤上去。這樣的話,可能丟失1秒的事務數據。
? ? ? innodb_flush_log_at_trx_commit=2時,在每次事務提交的時候會把log buffer刷到文件系統中去,但是每隔一秒調用文件系統的“flush”操作將緩存刷新到磁盤上去。如果只是MySQL數據庫掛掉了,由于文件系統沒有問題,那么對應的事務數據并沒有丟失。只有在數據庫所在的主機操作系統損壞或者突然掉電的情況下,數據庫的事務數據可能丟失1秒之類的事務數據。這樣的好處就是,減少了事務數據丟失的概率,而對底層硬件的IO要求也沒有那么高(log buffer寫到文件系統中,一般只是從log buffer的內存轉移的文件系統的內存緩存中,對底層IO沒有壓力)。MySQL 5.6.6以后,這個“1秒”的刷新還可以用innodb_flush_log_at_timeout 來控制刷新間隔。
? ?在大部分應用環境中,應用對數據的一致性要求并沒有那么高,所以很多MySQL DBA會設置innodb_flush_log_at_trx_commit=2,這樣的話,數據庫就存在丟失最多1秒的事務數據的風險。?
mysql還存在另外一種數據丟失,數據庫的復制丟失數據。
主從復制層面丟失數據 ??
? ? ? ?mysql的復制并不能很好地從服務器宕機,磁盤損壞、內存或網絡錯誤中恢復,這時一般得從某個點開啟重啟復制。
? ? ? ?這些情況包括:主庫意外關閉、備庫意外關閉、主庫上的二進制日志損壞、備庫上的中繼日志損壞、二進制日志與InnoDb事物日志不同步等。
?
總結
以上是生活随笔為你收集整理的mySQL 事物提交成功不等于数据保存成功的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 世界上最权威的68句创业名言
- 下一篇: 解决使用CSDN下载东西时,点击直接下载