MySQL學習筆記之四:併發控制和事務機制

一、mysql的併發控制

  當有多個查詢需要同時修改同一個數據,就會產生併發控制的問題。mysql可以在兩個層面進行併發控制:服務器層和存儲引擎層。

  mysql通過加鎖實現併發控制:

  ⑴鎖有兩類:

     讀鎖:共享鎖,即一個讀鎖不會阻塞其它讀鎖(但會阻塞其它寫鎖),多個用戶可同時讀取同一個資源,而不互相干擾。

     寫鎖:排他鎖,即一個寫鎖會阻塞其它讀寫鎖,在給定時間內,只有一個用戶能執行寫入。

  ⑵鎖粒度:

     表級鎖:鎖定整張表

     行級鎖:併發程度更高,但維護較麻煩,會增加系統開銷,易產生死鎖。級鎖只能在存儲引擎級別實現,MyISAM存儲引擎不支持行級鎖

  ⑶鎖分類:

     隱式鎖:由存儲引擎自動完成

     顯式鎖:用戶可手動施加鎖(表級鎖)

  ⑷手動加解鎖:服務器級別

     LOCK TABLES tb_name {READ|WRITE},...;

       例:lock tables students write;

     UNLOCK TABLES;

     FLUSH TABLES WITH READ LOCK;   #關閉所有已打開的表並全局施加讀鎖


     InnoDB存儲引擎也支持另外一種顯式鎖(只鎖定挑選出的行):

       SELECT ... LOCK IN SHARE MODE;

       SELECT ... FOR UPDATE;  


二、事務

  事務(Transaction)是訪問並可能更新數據庫中各種數據項的一個程序執行單元(unit);

  設想一個場景,A要向B轉賬500元,要經過兩個步驟:A從自己的賬戶中減去500元;向B的賬戶增加500元。顯而易見,只完成第一步或者只完成第二步都不合理,這兩個步驟必須放入一個事務中,當作一個不可分割的工作單位,要麼都執行,要麼都不執行。

  ⑴事務是恢復和併發控制的基本單位,要符合事務的概念,必須通過ACID測試:

     原子性(atomicity):一個事務是一個不可分割的工作單位,事務中包括的諸操作要麼都做,要麼都不做。

     一致性(consistency):事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。

     隔離性(isolation):一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。

     持久性(durability):持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的

  ⑵事務之間的隔離級別

     READ-UNCOMMITTED(讀未提交):事務中的修改,即使沒有提交,對其它事務也是可見的。事務可以讀取未提交的數據,這也稱爲“髒讀”;最低的隔離級別

     READ-COMMITTED(讀提交):一個事務開始時,只能“看見”已提交的事務所做的修改,因此,再次執行同樣的查詢,可能得到不一樣的結果,稱爲“不可重複讀”。

     REPEATABLE-READ(可重讀):保證了在同一個事務中多次讀取同樣記錄的結果是一致的,可能引起“幻讀”;mysql默認隔離級別

     SERIALIZABILE(可串行化):加鎖讀,即事務請求不到鎖就無法讀,必須等到其它事務釋放鎖(提交或回滾)後才行。

  ⑶查看mysql的隔離級別:SELECT @@global.tx_isolation;

  ⑷事務的啓動、提交和加滾:

     啓動:START TRANSACTION|BEGIN;

     提交:COMMIT;

     回滾:ROLLBACK;

     保存點:SAVEPOINT identifier;

     回滾至某個保存點:ROLLBACK [WORK] TO [SAVEPOINT] identifier;

     刪除某保存點:RELEASE SAVEPOINT identifier;     

  ⑸MySQL的自動提交功能:SELECT @@GLOBAL.autocommit;

     默認是啓用的,修改autocommit僅對支持事務的存儲引擎產生影響;

     自動提交能保證數據及時寫入磁盤,但會造成頻繁I/O,降低系統性能

  ⑹MVCC多版本併發控制;通過保存數據在某個時間點的快照實現。無論事務執行多長時間,其看到的數據都是一致的。根據事務開始的時間不同,每個事務對同一張表、同一時刻看到的數據可能是不一樣的。MVCC僅在第二、第三隔離級別下有效;

  ⑺事務日誌將隨機I/O轉換爲順序I/O,以提升事務操作效率;事務日誌也稱爲Write-Ahead Logging。

     數據從內存->事務日誌->數據文件

     爲減輕磁盤壓力,宜將事務日誌和數據文件放於不同的磁盤上,事務日誌不宜太大

  ⑻InnoDB支持事務,而MyISAM不支持


 會話1:

這裏要注意:修改全局變量針對新建立的會話生效,而修改局部變量則立即生效
MariaDB [testdb]> set session tx_isolation = 'REPEATABLE-READ';   #將會話級的事務隔離級別改爲“讀提交”
Query OK, 0 rows affected (0.00 sec)

MariaDB [testdb]> start transaction;    #啓動一個事務
Query OK, 0 rows affected (0.00 sec)

MariaDB [testdb]> select * from students;
+----+-------+------+--------+-------+
| ID | Name  | Age  | Gender | Class |
+----+-------+------+--------+-------+
|  1 | jerry | NULL | f      | NULL  |
|  2 | tom   | NULL | m      | NULL  |
+----+-------+------+--------+-------+
2 rows in set (0.08 sec)

 會話2:

MariaDB [testdb]> set session tx_isolation = 'REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)

MariaDB [testdb]> start transaction;   #在會話2中也啓動一個事務
Query OK, 0 rows affected (0.00 sec)

MariaDB [testdb]> insert students (Name,Gender) value ('rose','f');   #插入數據
Query OK, 1 row affected (0.08 sec)

 會話1:

MariaDB [testdb]> select * from students;   #會話1的事務看到的數據仍是原來的值
+----+-------+------+--------+-------+
| ID | Name  | Age  | Gender | Class |
+----+-------+------+--------+-------+
|  1 | jerry | NULL | f      | NULL  |
|  2 | tom   | NULL | m      | NULL  |
+----+-------+------+--------+-------+
2 rows in set (0.00 sec)

 會話2:

MariaDB [testdb]> commit;   #事務2提交
Query OK, 0 rows affected (0.01 sec)

 會話1:

MariaDB [testdb]> select * from students;   #事務2可以看到事務1提交後的數據了
+----+-------+------+--------+-------+
| ID | Name  | Age  | Gender | Class |
+----+-------+------+--------+-------+
|  1 | jerry | NULL | f      | NULL  |
|  2 | tom   | NULL | m      | NULL  |
|  6 | rose  | NULL | f      | NULL  |
+----+-------+------+--------+-------+
3 rows in set (0.00 sec)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章