事務
現在的軟件都是大併發的操作數據,然而爲了保證操作數據的正確性。就提出了事務。
事務的特性
事務必須滿足的4個條件(ACID):原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)。
- 原子性:一個事務(Transaction)中的所有操作要麼都執行成功,要麼都失敗。事務在執行過程中,如果發生錯誤則會回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過。數據不會有任何改變。
- 一致性:在事務開始前和結束後,數據的完整性沒有被破壞。
- 隔離性:數據庫允許多個事務併發對其數據進行讀取和修改,隔離性是防止多個事務交叉執行時讀取數據不一致問題。事務的隔離級別分爲,未提交讀(Read uncommitted)、提交讀(Read committed)、可重複讀(Repeatable read)和串行化(Serializable)。
- 持久性:事務提交後,對數據的修改是永久性的,提交的數據不會丟失。
事務的隔離級別
- 未提交讀(Read uncommitted):可以讀取其它所有事務未提交事務的執行結果。讀取未提交的數據,稱之爲髒讀(Dirty Read)。
- 提交讀(Read committed):一個事務只能讀取其它事務已提交的數據。
- 可重複讀(Repeatable read):保證同一事務的多個實例在併發讀取數據時,會看到同樣的數據行。MySQL默認隔離級別。
- 串行化(Serializable):每個事務排隊執行,最高的隔離級別,避免了髒讀、不可重複讀、幻讀。
舉例
- 用到的MySQL命令
命令 | 作用 |
---|---|
select version(); | 查看數據庫版本 |
select @@tx_isolation;# 8以前版本 select @@transaction_isolation;# 8以後版本 |
查看當前事務隔離級別 |
set session transaction isolation level 隔離級別 | 當前會話的隔離級別 |
start transaction | 開啓事務 |
commit | 提交事務 |
rollback | 回滾事務 |
- 建表
CREATE TABLE `tb_account` (
`id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`name` varchar(10) DEFAULT NULL COMMENT '姓名',
`balance` decimal(10,4) DEFAULT NULL COMMENT '餘額',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 髒讀
順序 | 會話1 | 會話2 |
---|---|---|
1 | # 設置隔離級別爲 未提交讀 set session transaction isolation level read uncommitted; |
|
2 | # 開啓事務 start TRANSACTION; |
# 開啓事務 start TRANSACTION; |
3 | ||
4 | ||
5 | ||
6 | ||
7 |
在會話1中,順序7查詢結果爲會話2中未提交事務修改的數據,即是 髒讀。
- 不可重複讀
順序 | 會話1 | 會話2 |
---|---|---|
1 | # 設置隔離級別爲 提交讀 set session transaction isolation level read committed; |
|
2 | # 開啓事務 start TRANSACTION; |
# 開啓事務 start TRANSACTION; |
3 | ||
4 | ||
5 |
在會話1中,順序3和5讀取到的數據不同,是因爲其間會話2對數據進行了修改,並提交。如果不提交,查詢餘額依然是0,避免了髒讀。一個事務中兩次的查詢結果不一致,即爲不可重複讀。
- 可重複讀
順序 | 會話1 | 會話2 |
---|---|---|
1 | # 設置隔離級別爲 可重複讀 set session transaction isolation level REPEATABLE read; |
|
2 | # 開啓事務 start TRANSACTION; |
# 開啓事務 start TRANSACTION; |
3 | ||
4 | ||
5 |
與不可重複讀的區別在於,無論會話2的事務是否已經提交,都不會改變會話1的查詢結果。
- 幻讀
所謂幻讀,指的是當某個事務在讀取某個範圍內的記錄時,另外一個事務又在該範圍內插入了新的記錄,當之前的事務再次讀取該範圍的記錄時,會產生幻行。InnoDB存儲引擎通過多版本併發控制(MVCC)解決了幻讀的問題。
順序 | 會話1 | 會話2 |
---|---|---|
1 | # 設置隔離級別爲 可重複讀 set session transaction isolation level REPEATABLE read; |
|
2 | # 開啓事務 start TRANSACTION; |
# 開啓事務 start TRANSACTION; |
3 | ||
4 | INSERT INTO tb_account VALUE (3, ‘王五’, 1000); COMMIT; |
|
5 |
在會話1中順序3查詢id爲3的記錄爲空,此時,會話2插入id爲3的數據,並提交。會話1再去插入id爲3的數據時就會報主鍵衝突異常。即爲幻讀。
防止讀到修改或刪除數據需要加行級鎖。
防止讀到新增數據一般就需要加表級鎖。
不可重複讀和幻讀的區別在於,不可重複讀會讀到修改或者刪除的數據,幻讀是會讀到其它事務已提交的數據。