本文實例講述了mysql的事務,隔離級別和鎖用法。分享給大家供大家參考,具體如下:
事務就是一組一起成功或一起失敗的sql語句。事務還應該具備,原子性,一致性,隔離性和持久性。
一、事務的基本要素 (acid)
1、原子性:事務開始后,所有的操作,要么全部成功,要么全部失敗,不可能處于中間狀態,事務是一個不可分割的整體,就像原子一樣。
2、一致性:事務開始前和結束后,數據庫的完整性約束沒有破壞,a向b轉賬,a扣了錢,但b卻沒到賬。
3、隔離性:同時發生的事務(并發事務)不應該導致數據庫處于不一致的狀態中,每個事務都獨立執行,不影響其他事務的存在。
4、持久性:事務對數據庫的更改都會保存在磁盤上,不會丟失。
二、事務的并發問題
1、臟讀:事務a讀取了事務b未提交的寫入數據,讀取到的數據就稱為臟數據
2、不可重復讀:事務a多次讀取同一數據,但在讀取過程中,事務b對數據做了修改,并提交了。導致多次讀取同一數據,結果不一樣。
3、幻讀:事務a對表中所有數據行進行了修改,比如設置status = 1,但同時,事務b往該表插入了一行新數據status = 0,對于操作事務a的用戶而言,表中還有一條記錄沒被修改,就像發生幻覺一樣。
三、事務隔離性的四個級別
事務隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
讀取未提交 read uncommitted |
√ |
√ |
√ |
讀已提交 read committed |
× |
√ |
√ |
可重復讀取 repeatable read |
× |
× |
√ |
序列化 serializable |
× |
× |
× |
四、獲取和設置數據庫隔離級別
1
2
|
show variables like '%isolation%' ; show global variables like '%isolation%' ; |
使用系統變量查詢
1
2
3
|
select @@ global .tx_isolation; select @@session.tx_isolation; select @@tx_isolation; |
對于mysql8而言,使用下面的變量進行查詢
1
2
3
|
select @@ global .transaction_isolation; select @@session.transaction_isolation; select @@transaction_isolation; |
設置隔離級別
1
2
3
|
set global tx_isolation = '隔離級別' ; set session tx_isolation = '隔離級別' ; set @@tx_isolation = '隔離級別' ; |
對于mysql8而言,使用下面語句進行設置
1
2
3
|
set global transaction_isolation = '隔離級別' ; set session transaction_isolation = '隔離級別' ; set @@transaction_isolation = '隔離級別' ; |
五、通過例子說明各隔離級別的情況
先準備一張表,和一點數據。
1
2
3
4
5
6
7
8
9
|
create table `account` ( `id` int (11) unsigned not null auto_increment comment 'id' , ` name ` varchar (32) default '' comment '名稱' , `money` decimal (11,2) default '0.00' comment '金錢' , primary key (`id`) ) engine=innodb default charset=utf8mb4; insert into `account` (` name `, `money`) values ( 'a' , '500.00' ); insert into `account` (` name `, `money`) values ( 'b' , '100.00' ); |
1、讀取未提交
1
2
|
set transaction_isolation = 'read-uncommitted' ; set autocommit = 0; |
事務b修改了表中的數據,但是未提交,事務a確讀取到了修改后的數據。如果因為某些原因,事務b回滾了,事務a讀取的這個數據就是臟數據。
2、讀已提交
1
2
|
set transaction_isolation = 'read-committed' ; set autocommit = 0; |
事務b修改數據但沒有提交,那么事務a仍然獲取的原來數據,解決了臟讀的問題。
但是事務b提交,事務a執行上一次查詢,結果與上一次查詢不一致,這就產生不可重復讀的問題。
3、可重復讀取
1
2
|
set transaction_isolation = 'repeatable-read' ; set autocommit = 0; |
事務b修改了數據并提交了,事務a兩次查詢的結果是一致的,解決了不可重復讀的問題。
這個時候,事務a去修改name為a的money數據
name為a的money變成了350,而不是400,可重復讀保證了數據的一致性。
我們重新在事務a中修改所有賬號的money等于200,同時在事務b中插入一條新的數據。
事務a中獲取的仍然是兩條數據,解決了新增數據時,事務a出現的幻讀問題。
4、序列化
1
2
|
set transaction_isolation = 'serializable' ; set autocommit = 0; |
事務a對表進行查詢,如果沒有提交,則事務b的插入語句一直等待在那里,直到超時或事務a提交。
反之,事務b對表進行插入后,沒有提交,則事務a對表的查詢也一直等待,直到事務b提交。
此時對表的讀寫都會進行鎖表,當然對并發性能的影響也比較大。
隔離級別越高,越能保證數據的完整性和一致性。
六、mysql的鎖
鎖分為兩種類型:
內部鎖:mysql服務器內部執行的內部鎖,以管理多個會話對表內容的爭用。
外部鎖:mysql為客戶會話提供顯式地獲取表鎖,以阻止其他會話訪問表。
內部鎖又會為兩種類型:
1、行級鎖:行級鎖是細粒度的,只有被訪問的行會被鎖定,這允許多個會話同時進行寫訪問。
2、表級鎖:mysql對myisam,memory和merge表使用表級鎖,一次只允許一個會話更新表,這使得這些存儲引擎更適用于以讀取為主的操作。
外部鎖:可以使用 lock table 和 unlock table 來控制鎖定。
read (共享鎖) :多個會話可以從表中讀取數據而不需要獲取鎖,此外,多個會話可以在同一表上獲得鎖,當 read 鎖時,沒有會話可以將數據寫入表中。任何寫入操作都將處于等待狀態,直到 read 鎖被釋放。
write (排他鎖) :當表被 write 鎖定時,除持有該鎖的會話外,其他會話都不能讀取或寫入數據,除非 write 鎖被釋放。
鎖表的語句:
1
|
lock tables table_name [ read | write]; |
解鎖表的語句:
1
|
unlock tables; |
鎖定數據庫中所有表:
1
|
flush tables with read lock; |
希望本文所述對大家MySQL數據庫計有所幫助。
原文鏈接:https://www.cnblogs.com/jkko123/p/10181870.html