Mysql事務原理介紹


事務

     一個事務會涉及到大量的cpu計算和IO操作,這些操作被打包成一個執行單元,要么同時都完成,要么同時都不完成.

     事務是一組原子性的sql命令或者說是一個獨立的工作單元,如果數據庫引擎能夠成功的對數據庫應用該組的全部sql語句,那么就執行該組命令

     如果其中有任何一條語句因為崩潰或者其它原因無法執行,那么該組中所有的sql語句都不會執行

     如果沒有顯示啟動事務,數據庫會根據autocommit的值.默認每條sql操作都會自動提交.

   原子性

        一個事務中的所有操作,要么都完成,要么都不執行.對於一個事務來說,不可能只執行其中的一部分.

   一致性

       數據庫總是從一個一致性的狀態轉換到另外一個一致性狀態.

   隔離性

       一個事務所做的修改在最終提交以前,對其它事務是不可見的.多個事務之間的操作相互不影響. 每降低一個事務隔離級別都能提高數據庫的並發

       1.讀未提交          其它事務未提交就可以讀
       2.讀已提交          其它事務只有提交了才能讀
       3.可重復讀          只管自己啟動事務時候的狀態,不受其它事務的影響(mysql默認)
       4.事務串行          按照順序提交事務保證了數據的安全性,但無法實現並發

   持久性

          一旦一個事務已經提交了,就算服務器崩潰,仍然需要在下次啟動的時候自動恢復.

         結合事務日志完成:

                事務日志寫入磁盤的時候是順序IO,寫數據文件的時候是隨機IO

         一旦事務提交了,必須立即執行一個IO操作,確保此事務立即寫入磁盤.

                

事務的狀態

      活動

      部分提交

      失敗

      中止

      提交

            事務一旦成功提交,便無法再撤銷.

 

 

事務並發訪問控制方式:

    鎖

    時間

    多版本和快照隔離(mvcc)

    MVCC是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低,雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要的行.

    MVCC的實現是通過保存數據在某個時間點的快照來實現的,也就是說,不管需要執行多長時間,只要事務開始時間相同,每個事務看到的數據都是一致的,事務開始的時間不同時,每個事務對同一張表,同一時刻看到的數據可能是不一樣的(因為不同的時間點可能數據就已經產生了不同的快照版本,而每個事務在默認的RR隔離級別下只能看到事務開始時的數據快照)

 innodd的mvcc是通過在每行記錄后面保存兩個隱藏列來實現的.這兩個列,一個保存了行的創建時間.一個保存了行的過期時間(刪除時間).列里面存儲的並不是實際的時間值.而是系統版本號.每開啟一個新的事務,系統版本號都會自動遞增.

  一個事務在開啟的時刻的系統版本號作為當前事務的版本號,用來和查詢到的每行記錄的版本號做對比.mvcc具體操作如下:

  select:

   A:過濾創建版本

      innodb只查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要么是在事務開始之前已經存在,要么是事務自身插入或修改的數據.

  B: 過濾刪除版本

       行的刪除版本要么未定義,要么大於當前事務版本號,這可以確保事務讀取到的行,在事務開始之前未被刪除(即,這樣做的目的是為了事務不會讀取到被真正刪除的行,刪除版本號小於當前事務版本號的表示操作刪除記錄的事務已經提交--數據已經被刪除,刪除版本號大於當前事務版本號的表示這個事務是在當前事務之后開始的--當前事務開始時這些記錄是還存在的,根據事務的隔離性,一致性要求,之后開始的事務操作的記錄並提交,對當前事務不可見,所以還需要當前事務能夠查詢這些記錄--只能夠查詢,不能夠修改和刪除)

只有滿足以上兩個條件的才可以返回作為查詢結果

 

insert:

      innodb為新插入的每一行保存當前系統版本號作為行版本號

 

delete:

      innodb為刪除的每一行保存當前系統版本號作為行刪除標識

 

update:

     innodb為插入一行新記錄,保存當前系統版本號作為行版本號

     修改表中原來行把當前系統版本號更新到原來的行作為行刪除版本號

 

保存這兩個額外的系統版本號,使大多數讀操作都可以不用加鎖,這樣設計使得讀數據操作很簡單,性能很好,並且也能保證只會讀取到符合標准的行,不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。

MVCC只在repeatable-read和read-committed兩個隔離級別下才工作,其他兩個隔離級別都和MVCC不兼容,因為read uncommitted總是讀取最新的數據行,而不是符合當前事務版本的數據行,而serializeble則會對所有讀取的行都加鎖。

另外要注意:MVCC在RR和RC隔離級別下的區別,在RR隔離級別下,一個事務只能讀取到事務開始的那個時刻的數據快照,即,別的事務修改並提交的數據在自身沒有提交之前一般讀取不到(加for update語句的select除外,因為這個語句要對數據加X鎖必須讀取最新的數據快照),在RC隔離級別下,事務總是讀取數據行的最新快照,即會產生不可重復讀的問題。

      

死鎖

    兩個或者多個事務在同一資源上相互占用,並請求鎖定對方占用的資源的狀態

 

 

事務提交

    自動提交

     mysql默認采用自動提交(AUTOCOMMIT)模式.如果沒有顯示的開始一個事務,那么每條sql語句都會被當作一個事務執行提交的操作

     當AUTOCOMMIT=0的時候所有的sql語句都是在一個事務中,直到顯示的執行COMMIT和ROLLBACK回滾該事務結束.同時又開始了另外一個新的事務.

 

    顯式提交

     開啟事務

            START TRANSACTION 

     結束事務

          (1)  COMMIT:         提交 

          (2)  ROLLBACK:    回滾 

   

     注意:一旦一個事務成功提交,將無法回滾.一個事務要想回滾,只能在沒有提交成功之前執行回滾

                只有事務型存儲引擎中的DML語句方能支持此類操作

     建議:顯式請求和提交事務,而不要使用“自動提交”功能 set autocommit={1|0}

     事務支持保存點 savepoint:

            SAVEPOINT identifier

            ROLLBACK [WORK] TO [SAVEPOINT]  identifier

            RELEASE SAVEPOINT identifier

 

事務日志

     事務要保證ACID的完整性必須依靠事務日志做跟蹤,每一個操作在真正寫入數據數據庫之前,先寫入到日志文件中
     如要刪除一行數據會先在日志文件中將此行標記為刪除,但是數據庫中的數據文件並沒有發生變化.

     只有在(包含多個sql語句)整個事務提交后,再把整個事務中的sql語句批量同步到磁盤上的數據庫文件

     在事務引擎上的每一次寫操作都需要執行兩遍:
        1.先寫入日志文件中
                寫入日志文件中的僅僅是操作過程,而不是操作數據本身,所以速度比寫數據庫文件速度要快很多.
        2.然后再寫入數據庫文件中

                寫入數據庫文件的操作是重做事務日志中已提交的事務操作的記錄.

    日志組
         一般不止設置一個日志文件,一個文件寫滿之后使用另外一個日志文件提高服務器效率.

    日志文件的日志同步到磁盤后空間會自動釋放,單個日志文件不宜設置過大     如果日志文件過大mysql進程在把日志同步到數據文件的時候可能會崩潰

  事務日志的用途

      事務日志可以幫助提高事務的效率,使用事務日志,存儲引擎在修改表的數據的時候只需要修改其內存拷貝,再把該行為記錄到持久在磁盤的事務日志中.而不用每次都將修改的數據本身持久到磁盤.事務日志采用的是追加方式,因此寫日志的操作是磁盤上一小塊區域的順序IO,而不像隨機IO需要磁盤在多個地方移動.所以采用事務日志的方式相對來說要快的多,事務日志持久后,內存中的修改在后台慢慢的刷回磁盤.期間如果系統發生崩潰,存儲引擎在重啟的時候依靠事務日志自動恢復這部分被修改數據

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM