天天看點

MySql 事務與鎖

事務介紹

首先,什麼是事務?事務就是一段sql 語句的批處理,但是這個批處理是一個atom(原子),不可分割,要麼都執行,要麼復原(rollback)都不執行。

MySQL 事務主要用于處理操作量大,複雜度高的資料。比如說,在人員管理系統中,你删除一個人員,你即需要删除人員的基本資料,也要删除和該人員相關的資訊,如信箱,文章等等,這樣,這些資料庫操作語句就構成一個事務!

  • 在 MySQL 中隻有使用了 Innodb 資料庫引擎的資料庫或表才支援事務。
  • 事務處理可以用來維護資料庫的完整性,保證成批的 SQL 語句要麼全部執行,要麼全部不執行。
  • 事務用來管理 insert,update,delete 語句

一般來說,事務是必須滿足4個條件(ACID): Atomicity(原子性)、Consistency(穩定性)、Isolation(隔離性)、Durability(可靠性)

  • 1、事務的原子性:一組事務,要麼成功;要麼撤回。
  • 2、穩定性 :有非法資料(外鍵限制之類),事務撤回。
  • 3、隔離性:事務獨立運作。一個事務處理後的結果,影響了其他事務,那麼其他事務會撤回。事務的100%隔離,需要犧牲速度。
  • 4、可靠性:軟、硬體崩潰後,InnoDB資料表驅動會利用日志檔案重構修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 選項 決定什麼時候吧事務儲存到日志裡。
MySql 事務與鎖

事務并發并不進行事務隔離造成的髒讀、幻讀、不可重複讀

  • 髒讀:事務A讀到未送出事務B修改的資料,如果此時事務B中途執行失敗復原,那麼此時事務A讀取到的就是髒資料。比如事務A對money進行修改,此時事務B讀取到事務A的更新結果,但是如果後面事務A復原,那麼事務B讀取到的就是髒資料了。
  • 不可重複讀:同一個事務中,對同一份資料讀取的結果不一緻。事務A在事務B對資料更新前進行讀取,然後事務B更新送出,事務A再次讀取,這時候兩次讀取的資料不同。
  • 幻讀:(同一個事務中,同一個查詢多次傳回的結果不一樣。事務B查詢表的記錄數,然後事務A對表插入一條記錄,接着事務B再次查詢發現記錄數不同。注意這個解釋是不正确,網絡上有很多這樣的解釋,包括我認為比較權威的專家,但是經過實驗發現并不正确。是以這是需要注意的)。可以做這樣一個實驗,事務A查詢記錄數,事務B插入一條記錄(主鍵值為6),送出,然後事務A查詢記錄數,發現記錄數沒有改變,但是此時插入一條主鍵值為6的記錄發現沖突了,感覺像出現了幻覺。

差別

1、髒讀和不可重複讀:髒讀是事務讀取了還未送出事務的更新資料。不可重複讀是同一個事務中,幾次讀取的資料不同。

2、不可重複讀和幻讀的差別:都是在同一個事務中,前者是幾次讀取資料不同,後者是幾次讀取資料整體不同。

隔離級别

MySql 事務與鎖
作用
Serializable(串行化) 避免髒讀、不可重複讀、幻讀
Repeatable(可重複讀) 避免髒讀、不可重複讀
Read committed(讀已送出) 避免髒讀
Read uncommitted(讀未送出) none
  • 隔離級别改變影響鎖的周期
  • mysql支援上面4種隔離級别,預設為可重複讀
MySql 事務與鎖

 鎖

MySql 事務與鎖

MySQL有三種鎖的級别:頁級、表級、行級。

  MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);

  BDB存儲引擎采用的是頁面鎖(page-level locking),但也支援表級鎖;

  InnoDB存儲引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是采用行級鎖。

MySQL這3種鎖的特性可大緻歸納如下:

1、表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的機率最高,并發度最低。

  表級鎖讓多線程可以同時從資料表中讀取資料,但是如果另一個線程想要寫資料的話,就必須要先取得排他通路(預設加排他表鎖);(共享讀鎖(Table Read Lock))

  更新資料時,必須要等到更新完成了,其他線程才能通路(讀)這個表。(獨占寫鎖(Table Write Lock))

2、行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。

3、頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。

原則上資料表有一個讀鎖時,其它程序無法對此表進行更新操作,但在一定條件下,MyISAM表也支援查詢和插入操作的并發進行。

一般MyISAM引擎的表也支援查詢和插入操作的并發進行(原則上資料表有一個讀鎖時,其它程序無法對此表進行更新操作)

  MyISAM引擎有一個系統變量concurrent_insert,專門用以控制其并發插入的行為,其值分别可以為0、1或2:  

    a、concurrent_insert為0,不允許并發插入。
    b、concurrent_insert為1,如果MyISAM表中沒有空洞(即表的中間沒有被删除的行),MyISAM允許在一個程序讀表的同時,另一個程序從表尾插入記錄。這也是MySQL的預設設定。
    c、concurrent_insert為2,無論MyISAM表中有沒有空洞,都允許在表尾并發插入記錄。      

如果有讀寫請求同時進行的話,MYSQL将會優先執行寫操作。這樣MyISAM表在進行大量的更新操作時(特别是更新的字段中存在索引的情況下),會造成查詢操作很難獲得讀鎖,進而導緻查詢阻塞。

我們還可以調整MyISAM讀寫的優先級别:

  a、通過指定啟動參數low-priority-updates,使MyISAM引擎預設給予讀請求以優先的權利。

  b、通過執行指令SET LOW_PRIORITY_UPDATES=1,使該連接配接發出的更新請求優先級降低。

  c、通過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優先級。

MyISAM使用的是 flock 類的函數,直接就是對整個檔案進行鎖定(叫做檔案鎖定),MyISAM的資料表是按照單個檔案存儲的,可以針對單個表檔案進行鎖定;

InnoDB使用的是 fcntl 類的函數,可以對檔案中局部資料進行鎖定(叫做行鎖定),InnoDB是一整個檔案,把索引、資料、結構全部儲存在 ibdata 檔案裡,是以必須用行鎖定。

事物控制語句:

BEGIN或START TRANSACTION;顯式地開啟一個事務;

    COMMIT;也可以使用COMMIT WORK,不過二者是等價的。COMMIT會送出事務,并使已對資料庫進行的所有修改稱為永久性的;

    ROLLBACK;有可以使用ROLLBACK WORK,不過二者是等價的。復原會結束使用者的事務,并撤銷正在進行的所有未送出的修改;

    SAVEPOINT identifier;SAVEPOINT允許在事務中建立一個儲存點,一個事務中可以有多個SAVEPOINT;

    RELEASE SAVEPOINT identifier;删除一個事務的儲存點,當沒有指定的儲存點時,執行該語句會抛出一個異常;

    ROLLBACK TO identifier;把事務復原到标記點;

    SET TRANSACTION;用來設定事務的隔離級别。InnoDB存儲引擎提供事務的隔離級别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。      

MYSQL 事務處理主要有兩種方法:

1、用 BEGIN, ROLLBACK, COMMIT來實作

BEGIN 開始一個事務
    ROLLBACK 事務復原
    COMMIT 事務确認      

2、直接用 SET 來改變 MySQL 的自動送出模式:

SET AUTOCOMMIT=0 禁止自動送出
    SET AUTOCOMMIT=1 開啟自動送出      

注意點

1、如果事務中sql正确運作,後面沒有commit,結果是不會更新到資料庫的,是以需要手動添加commit。

2、如果事務中部分sql語句出現錯誤,那麼錯誤語句後面不會執行。而我們可能會認為正确操作會復原撤銷,但是實際上并沒有撤銷正确的操作,此時如果再無錯情況下進行一次commit,之前的正确操作會生效,資料庫會進行更新。

參考連結:

https://www.cnblogs.com/leonardchen/p/7048187.html

https://www.cnblogs.com/metoy/p/5545580.html

http://blog.csdn.net/andyxm/article/details/44810313

作者:Eric Li

出處:http://www.cnblogs.com/ericli-ericli/

除轉載文章外,随筆版權歸作者和部落格園所有,歡迎轉載,轉載請标明出處。

如果您覺得本篇博文對您有所收獲,覺得作者還算用心,請點選右下角的 [推薦],謝謝!

繼續閱讀