併發控制:併發控制對於任何一個容許多個用戶連入進來並請求資源的服務來說都是必需要完成的功能
MySQL做爲服務器來說,其內部有不少數據有不少張表,表中有數據,不管是myisam仍是InnoDB存儲引擎對於單張表來說若是沒作分區,那麼其數據都放在同一個文本文件,當兩個客戶端同時發起MySQL會話,連入MySQL時,MySQL服務會啓動兩個會話線程來給兩個用戶創建鏈接,假如第一個用戶發起select語句查詢表中的全部行,如表tb1,而第二個用戶但願在表中同時要插入數據,那麼這兩條語句可否同時執行?若是插入語句恰好插入一半查詢語句剛查到了剛插入的語句,那麼查詢的結果就不完整了,所以當併發有不少用戶同時訪問時,必須使用一種機制來實現其內部數據的併發訪問控制,以保證每一個用戶所看到的數據儘量是完整的。所以不管任什麼時候候,只要有多個查詢須要在同一時刻修改數據,都會產生併發控制問題。
MySQL是插件式存儲引擎,及其併發訪問控制能夠在兩個層次上完成,1.MySQL的核心程序【MySQL內部完成】2.MySQL存儲引擎層完成
在兩個層次上實現:
MySQL併發訪問控制大多數狀況下都應該由存儲引擎自動完成,存儲引擎自身會實現對文件進行加鎖並且是隱式鎖,由存儲引擎自動完成。如:未來要備份數據,若是要備份很大的數據集,備份和修改的時間點不一致,數據拿來使用也是無法用的,必要時要備份整個數據集就必須對整個數據進行加鎖,禁止任何人修改,把數據複製一份來作備份,必需要施加一個全局鎖,就能夠在服務器層來完成。
服務器層
存儲引擎層
MySQL在大多數狀況下能夠實現併發控制,尤爲在支持事務引擎的存儲引擎,其底層實現了併發控制的細節和複雜度很是高。
鎖:lock
對於數據庫的數據訪問來說,鎖通常分兩類
兩類:
讀鎖:共享鎖
寫鎖:獨佔鎖 拒絕其餘人同時使用
鎖粒度:在表修改時是1到3行,而查找是在10行之後,沒有關聯性,能不能同時執行就取決於鎖粒度。若是是修改時就必須鎖表,那麼後面就不能查詢了
表級鎖 鎖一張表 myisam是表級鎖若是是數據倉庫,一個數據造成之後,不多改了,一次寫屢次讀,就用表級鎖
行級鎖 鎖定時,只須要鎖相關的行 InnoDB是行級鎖,若是是讀寫訪問操做同樣多,選擇行級鎖,在線事務處理的場景通常都是用InnoDB存儲引擎, 鎖控制很是複雜,鎖狀態維護和檢查很是麻煩,容易產生死鎖
在行級鎖內部必需要隨時監控死鎖發生的位置,若是發生了,則須要讓一個後退,釋放一個資源,讓另一個先使用
死鎖:
如表中有兩行1,2
A: 1, 其中A回話須要對1,2行加鎖來作操做,此時已請求了1行鎖,再去請求第2行時,發現B回話鎖定了第2行,B也須要使用第1行,此時B須要請求第1行,在互相請求對方鎖定的資源時,結果就出現死鎖
存儲引擎層施加的鎖由存儲引擎本身實現隱式維護的
鎖分類:
隱式鎖:由存儲引擎自動完成
顯式鎖:用戶可手動施加鎖,表級鎖
手動加鎖:服務器級別實現的
LOCK TABLES tb1 {READ|WRITE},... 對錶請求施加鎖,能夠指定多個表用','分開,若是請求時,別人鎖定了就要延遲一段時間才能請求到,必需要等到別人釋放鎖,才能獲取到鎖
UNLOCK TABLES 釋放全部鎖
FLUSH TABLES WITH READ LOCK; 關閉表,請求施加全部表的讀鎖
UNLOCK TABLES;
MariaDB [hellodb]> lock tables students read;
Query OK, 0 rows affected (0.00 sec)
只要不釋放,鎖將一直存在
用別的回話請求能夠讀students表
往表中插入數據
新開的會話
MariaDB [(none)]> insert into hellodb.students (Name,Age) values ('liufang',23);插入數據時會一直處於等待狀態,由於添加了讀鎖,若是不釋放鎖,此處將沒法執行,讀鎖能夠共享給讀可是不能共享給寫,寫鎖是排他
釋放鎖後立刻就能夠寫入成功了
MariaDB [hellodb]> unlock tables;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> insert into hellodb.students (Name,Age) values ('liufang',23);
Query OK, 1 row affected (31.95 sec) 用來31.95s
施加寫鎖,本身會話讀寫都沒有問題,其餘會話讀寫就會處於等待狀態
MariaDB [(none)]> lock tables hellodb.students write;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> select * from hellodb.students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [(none)]> insert into hellodb.students (Name,Age) values ('yuanyou',25);
Query OK, 1 row affected (0.01 sec)
另外的會話
MariaDB [hellodb]> select * from hellodb.students where StuID<3;處於等待當中
取消鎖
ariaDB [(none)]> unlock tables;
Query OK, 0 rows affected (0.00 sec)
此時執行成功
MariaDB [hellodb]> select * from hellodb.students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (1 min 18.43 sec)sql
InnoDB存儲引擎也支持另一種顯式鎖(只鎖定挑選出的行):
SELECT ... LOCK IN SHARE MODE; 施加讀鎖
SELECT ... FOR UPDATE;
若是說一個數據庫存儲引擎是支持事務的,則事務是另一種併發訪問控制機制
事務:ACID【事務的目的也是實現併發訪問控制,並且事務自己是更高級別的訪問控制功能】
一個執行單元:多個SQL語句,要麼都執行,要麼都不執行;
以銀行轉帳列子
事務有兩類狀態:提交【執行成功,就所有成功】,回滾【事務失敗,所有失敗】
A:atomicity,原子性 執行單元那麼成功要麼失敗
C:consistency,一致性 一個一致性狀態轉到另外一個一致性狀態 如帳戶總額,加和減要一致
I:isolation,隔離性 一個事務在修改在提交以前其餘事務是不可見的,事務彼此之間是隔離的
隔離級別:關係型事務有4個級別
D:durability,持久性 一旦事務提交了,事務執行成功了,必須保證全部數據都可以永久存儲到持久存儲中去,必須保證數據是提交後的狀態。即使數據庫服務器發生崩潰,其數據依然能夠獲得。 不必定能達到100%,由於數據在內存中還沒寫到磁盤時就斷電了,那麼數據必定會丟失的。
機械硬盤寫的能力在80-100次之間每秒鐘,固態硬盤在300-500次之間每秒,PCI-E並行的固態硬盤能夠達到數萬到數十萬個io
事務的隔離級別:事務若是徹底執行隔離,因爲數據集不多,而一個事務中可能包含多個語句,一個事務一旦發起,那麼其餘事務就無法運行,因此併發性很低,隔離性是比想象複雜多,在sql標準上實現了四種隔離級別,每一種都對應了事務所作的修改。
MySQL隔離級別是經過一個參數來設定的
MariaDB [(none)]> show global variables like '%iso%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ | 是會話級別的動態變量,可在會話級別修改當即生效
+---------------+-----------------+
1 row in set (0.00 sec)
READ-UNCOMMITTED(讀未提交):最低隔離級別,會產生「髒讀」(還未提交就能讀到);你所看到的數據別人只要已改,你立刻看到,別人沒提交的數據也能夠看到,別人滾過去了也能夠看到,沒有隔離的意義,
READ-COMMTTED(讀提交):「不可重複讀」 產生的問題:好比在沒提交以前讀了一個數據是3,提交以後數字改成5了,再一次讀時是5了。這同一個事務在兩次執行時不同,在一個事務啓動起來之後,事務是隔離的,事務在啓動和不啓動之間所看到的數據都是同樣的纔對。先後讀取數據不一致。
REPEATABLE-READ(可重讀):「幻讀」 在一個事務內部,只要本身不提交,看到的都是如出一轍的,只有本身提交後,才能看到別人提交後的數據,爲避免幻讀使用下一種方法
SERIALIZABILE(可串行化):使用加鎖讀 先後都是一致的,當別人提交一個數據之後,數據提交了,看到的就是最終的數據,若是別人一個事務啓動起來還沒提交,要讀這個數據須要等到提交後才能讀。 可以提供最安全的數據保證,可是併發能力也是最低的。
級別越高併發性能越差,但數據安全程度越高
SELECT @@global.tx_isolation; 查看默認隔離級別
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
啓動事務:
START TRANSACTION
提交事務:COMMIT
回滾事務:ROLLBACK 執行後,前面那個執行的事務就回到初始值了(前提事務要未提交才能回滾到未更新狀態,提交後事務就完成了)
READ-UNCOMMITTED(讀未提交):最低隔離級別,會產生「髒讀」(還未提交就能讀到);你所看到的數據別人只要已改,你立刻看到,別人沒提交的數據也能夠看到,別人滾過去了也能夠看到
第1個會話
ariaDB [(none)]> set session tx_isolation='read-uncommitted';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set (0.00 sec)
MariaDB [(none)]> select @@session.tx_isolation; 該會話下事務級別修改爲功
+------------------------+
| @@session.tx_isolation |
+------------------------+
| READ-UNCOMMITTED |
+------------------------+
1 row in set (0.00 sec)
第2個會話
MariaDB [hellodb]> set session tx_isolation='read-uncommitted';
Query OK, 0 rows affected (0.00 sec)
手動的顯示啓動事務
start transaction
兩邊都啓動事務
MariaDB [(none)]> start transaction;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
把表students,Shi Potian Age改成200
MariaDB [hellodb]> select * from hellodb.students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
MariaDB [hellodb]> update students set Age=200 where StuID=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select Name,Age from students where StuID=2;
+------------+-----+
| Name | Age |
+------------+-----+
| Shi Potian | 200 |
+------------+-----+
1 row in set (0.00 sec)
MariaDB [(none)]> select * from hellodb.students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 | Age值已改
| 3 | Xie Yanke | 53 | M | 2 | 16 |
回滾事務,以上事務就結束了
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected, 1 warning (0.00 sec)
MariaDB [hellodb]> select Name,Age from students where StuID=2;
+------------+-----+
| Name | Age |
+------------+-----+
| Shi Potian | 200 | 發現沒有回滾回去
+------------+-----+
1 row in set (0.00 sec)
查看一下存儲引擎
MariaDB [hellodb]> show table status like 'students'\G
*************************** 1. row ***************************
Name: students
Engine: MyISAM 是myisam存儲引擎
Version: 10
Row_format: Dynamic
Rows: 27
Avg_row_length: 24
Data_length: 664
Max_data_length: 281474976710655
Index_length: 2048
Data_free: 0
Auto_increment: 28
Create_time: 2015-04-01 18:53:08
Update_time: 2015-04-02 13:42:01
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
myisam存儲引擎不支持事務,因此不能回滾
修改存儲引擎
MariaDB [hellodb]> alter table students engine=innodb; 此種修改方式很危險
Query OK, 27 rows affected (0.08 sec)
Records: 27 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> show table status like 'students'\G
*************************** 1. row ***************************
Name: students
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 27
Avg_row_length: 606
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 28
Create_time: 2015-04-02 14:31:10
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
會話1 提交事務
MariaDB [hellodb]> commit;
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
會話1
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> update students set Age=99 where StuID=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 99 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話1
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 99 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話2
MariaDB [hellodb]> rollback; 事務回滾
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 | 已經返回到未修改狀態了
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話1
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.00 sec)
READ-COMMTTED(讀提交):「不可重複讀」 產生的問題:好比在沒提交以前讀了一個數據是3,提交以後數字改成5了,再一次讀時是5了。這同一個事務在兩次執行時不同,在一個事務啓動起來之後,事務是隔離的,事務在啓動和不啓動之間所看到的數據都是同樣的纔對。先後讀取數據不一致。 提交後就能夠查看到。提交前和提交後讀是不一樣的,因此不可重複讀
會話1
MariaDB [hellodb]> set session tx_isolation='read-committed';
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> set session tx_isolation='read-committed';
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
會話1
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> update students set Age=60 where StuID=1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話2
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec) 未提交
會話1
MariaDB [hellodb]> commit; 提交
Query OK, 0 rows affected (0.01 sec)
會話2
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 | 能夠查看到了
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.00 sec)數據庫
REPEATABLE-READ(可重讀):「幻讀」 在一個事務內部,只要本身不提交,看到的都是如出一轍的,只有本身提交後,才能看到別人提交後的數據,爲避免幻讀使用下一種方法
會話1
MariaDB [hellodb]> set session tx_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> set session tx_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)
會話1
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
會話1
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> update students set Age=68 where StuID=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 68 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話2
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話1
MariaDB [hellodb]> commit;
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 200 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> update students set Age=Age+1 where StuID=2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 69 | M | 1 | 7 | 此時叫幻讀
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> commit;
Query OK, 0 rows affected (0.01 sec)
SERIALIZABILE(可串行化):使用加鎖讀 先後都是一致的,當別人提交一個數據之後,數據提交了,看到的就是最終的數據,若是別人一個事務啓動起來還沒提交,要讀這個數據須要等到提交後才能讀。 可以提供最安全的數據保證,可是併發能力也是最低的。
會話1
MariaDB [hellodb]> set session tx_isolation='serializable';
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> set session tx_isolation='serializable';
Query OK, 0 rows affected (0.00 sec)
會話1
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
會話2
MariaDB [hellodb]> start transaction;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 69 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> update students set Age=89 where StuID=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 89 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
會話1
MariaDB [hellodb]> select * from students where StuID<3;
處於等待狀態,由於事務沒有提交,只有等待對方提交了才能看到,保證看到的是最新的數據
只要對方釋放鎖了就能夠看到
會話2
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.00 sec)
會話1
MariaDB [hellodb]> select * from students where StuID<3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 69 | M | 1 | 7 |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (22.99 sec)
請求不到鎖就不會讀數據
爲了保證服務器有更好的並行性,也不至於數據彼此間影響過大,因此MySQL使用了可重讀,即使使用了可重讀,中間仍是會出現幻讀問題,由此建議用小事務替代大事務是比較理想的作法。默認狀況下InnoDB存儲引擎,默認會啓動自動提交功能
MariaDB [hellodb]> select @@global.autocommit;
+---------------------+
| @@global.autocommit |
+---------------------+
| 1 |
+---------------------+
1 row in set (0.00 sec)
手動指定sql語句沒指定事務,它會自動執行完每一條語句都提交一下
自動提交能保證sql語句執行完成,就可以獲得數據持久保證,可是會極大的下降系統性能
建議使用InnoDB存儲引擎時,把自動提交關閉,本身手動啓動事務手動提交事務
沒法autocommit是否爲1對myisam沒有影響,myisam不支持事務,myisam也是沒法回滾的
SAVEPOINT 保存點,回滾時,只回滾到保存的時間點
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier 回滾某個保存下來的位置
RELEASE SAVEPOINT identifier 釋放保存點
MariaDB [hellodb]> start transaction; 啓動事務
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from students where StuID > 3 and StuID<6;
+-------+-----------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-----------+-----+--------+---------+-----------+
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
+-------+-----------+-----+--------+---------+-----------+
2 rows in set (0.01 sec)
這裏修改數據
MariaDB [hellodb]> update students set Age=80 where StuID=5;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> savepoint oop;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delete from students where StuID=4 and StuID=5;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> savepoint ooo;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delete from students where StuID=4 and StuID=5;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> savepoint ooo;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delete from students where StuID=10;
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select * from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 60 | M | 2 | 3 |
| 2 | Shi Potian | 69 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 80 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
| 26 | liufang | 23 | F | NULL | NULL |
| 27 | yuanyou | 25 | F | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
26 rows in set (0.00 sec)
MariaDB [hellodb]> savepoint look;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> rollback to ooo;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from students where StuID=10;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.00 sec)
MariaDB [hellodb]> release savepoint oop;
Query OK, 0 rows affected (0.00 sec)
MySQL的自動提交功能:
SELECT @@GLOBAL.autocommit;
+---------------------+
| @@GLOBAL.autocommit |
+---------------------+
| 1 |
+---------------------+
MySQL下,事務經過事務日誌來保證其性能和ACID的測試的,依賴於事務日誌的功能
MVCC【Multiversion Concurrency Control多版本併發控制,對InnoDB來說啓動一個事務就至關於對MySQL中的全部數據作了一個快照,然後在快照的基礎上實現查找工做】: 經過保存數據在某個時間的快照實現。不管事務執行多長時間,其看到的數據都是一致的。
InnoDB這種存儲引擎其mvcc是在每行記錄後面添加了兩個隱藏字段,是看不到的,其中一個保存了行的建立時間,一個保存了行的過時時間或刪除時間【只是標記它看不到】。
MVCC僅在第2、第三隔離級別下有效;
事務日誌:目的將隨機I/O轉換爲順序I/O,以提高事務操做效率;事務日誌也稱爲Write-Ahead Logging 任何事務相關數據的修改都是先在內存中修改,修改後是不會組合,先寫到磁盤上一份然後寫到日誌文件中。事務日誌是一種追加式的log 因爲要寫兩次磁盤,性能比較差,如何下降其對磁盤io的影響?將數據文件和事務日誌放在不一樣的磁盤上,這樣能夠避免將事務回寫到數據文件中,但若是事務所在的磁盤壞了怎麼辦呢?所以事務日誌所在的硬盤應該具備容災性,好比說用raid1,或raid10, MySQL支持使用兩種事務日誌,一種寫 一種備份 事務日誌文件應該有多大?數據是否要在事務文件中一直存放着?放在事務文件中的存在的問題:有了事務日誌就能保存持久性,當服務器軟件程序崩潰,有些數據在事務文件沒在數據文件中,下次啓動時,必須想辦法把數據從事務日誌通通都寫到數據文件中去。並保證數據文件處於clean狀態,服務器纔可以繼續向外提供服務
,此過程就叫崩潰後恢復過程。若是事務文件很大,把事務文件寫到數據文件中都要很長時間,所以日誌文件必定不能太大,根據業務數據的容量來定大小。事務日誌文件是成組出現的,每一組當中不止一個 事務日誌兩個文件輪流使用,第一個文件填滿了,填第二個日誌文件,而此時把第一個日誌文件同步到數據文件中去。InnoDB存儲引擎自動管理的
數據從事務日誌寫到數據文件中,其頻繁度如何衡量?
越快,事務丟失的可能性越小,但磁盤io越大,是MySQL自我管理的
可是從內存同步到事務中必需要及時,只要一提交事務,就往事務日誌文件中寫
安全