1.事務的四大特性(ACID)
-
原子性(Atomicity)
原子性是指事務是一個不可分割的工作機關,事務中的操作要麼全部成功,要麼全部失敗。比如在同一個事務中的SQL語句,要麼全部執行成功,要麼全部執行失敗
-
一緻性(Consistency)
官網上事務一緻性的概念是:事務必須使資料庫從一個一緻性狀态變換到另外一個一緻性狀态。以轉賬為例子,A向B轉賬,假設轉賬之前這兩個使用者的錢加起來總共是2000,那麼A向B轉賬之後,不管這兩個賬戶怎麼轉,A使用者的錢和B使用者的錢加起來的總額還是2000,這個就是事務的一緻性。
-
隔離性(Isolation)
事務的隔離性是多個使用者并發通路資料庫時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作資料所幹擾,多個并發事務之間要互相隔離。
-
持久性(Durability)
持久性是指一個事務一旦被送出,它對資料庫中資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響。
事務的四大特性中最麻煩的是隔離性,下面重點介紹一下事務的隔離級别.
2.事務的隔離級别
多個線程開啟各自事務操作資料庫中資料時,資料庫系統要負責隔離操作,以保證各個線程在擷取資料時的準确性。
2.1事務不考慮隔離性可能會引發的問題
2.1.1.編寫測試SQL腳本,如下:
/*建立賬戶表*/
create table account(
id int primary key auto_increment,
name varchar(40),
money float
);
/*插入測試資料*/
insert into account(name,money) values('A',1000);
insert into account(name,money) values('B',1000);
insert into account(name,money) values('C',1000);
下面我們在MySQL資料庫中模拟A——B轉帳這個業務場景來說明事務問題
2.1.2.髒讀
髒讀就是指當一個事務正在通路資料,并且對資料進行了修改,而這種修改還沒有送出到資料庫中,這時,另外一個事務也通路這個資料,然後使用了這個資料。
-
例如:
A工資為1000,事務A中把他的工資減去100,再把B的工資加上100,但事務A尚未送出。
與此同時,
事務B正在查詢工資表,讀取到A的工資為900,B的工資為1100。
随後,
事務A發生異常,而復原了事務。A的工資又復原為1000,B的工資也復原為1000
最後,
最終事務B讀取到A的工資為900,B的工資為1100,事務B做了一次髒讀。
這是非常危險的,假設A向B轉帳100元,對應sql語句如下所示

髒讀最嚴重的事情、讀取資料是不真實的
2.1.2.不可重複讀
一個事務讀取另外一個送出過的資料。造成另外一個事務,多次讀取的内容不一緻,資料的内容的改變。—update
一個事務,讀取了另外一個事務送出了的資料。-----同一行資料。
資料的改變。—update
2.1.3.虛讀(幻讀)
虛讀:一個事務讀取另外一個事務已經送出的資料。但是這裡面強調的資料數目的改變。insert,delete。
一個事務讀取另外一個事務已經送出過的資料。 強調的是條目數的改變insert,delete
2.1.4.虛讀和不可重複讀對象
-
不可重複度–update
同一條記錄 内容的改變
-
虛讀—insert delete
條目數的改變
3.資料庫的事務隔離級别
3.1.資料庫4種隔離級别
MySQL資料庫共定義了四種隔離級别:
1.Read uncommitted(讀未送出):最低級别,以上情況均無法保證。
2.Read committed(讀已送出):可避免髒讀情況發生。Oracle的預設隔離級别
3.Repeatable read(可重複讀):可避免髒讀、不可重複讀情況的發生。MySQL預設
4.Serializable(串行化):可避免髒讀、不可重複讀、幻讀情況的發生。
不同的隔離級别對并發問題的解決情況如圖:
注意:事務的隔離級别和資料庫并發性是成反比的,隔離級别越高,并發性越低。
3.2.資料庫4種隔離級别示範
3.2.1.查詢資料庫的隔離級别
mysql資料庫查詢目前事務隔離級别:
select @@tx_isolation
mysql資料庫預設的事務隔離級别是:
Repeatable read(可重複讀)
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set
3.2.2.設定資料庫的隔離級别
mysql資料庫設定事務隔離級别:
set session transaction isolation level 隔離級别
示例:
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set
mysql> set session transaction isolation level Read uncommitted;
Query OK, 0 rows affected
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set
3.2.3.Read uncommitted
當把事務的隔離級别設定為read uncommitted時,會引發髒讀、不可重複讀和虛讀
- A視窗
--設定A使用者的資料庫隔離級别為Read uncommitted(讀未送出)
set transaction isolation level Read uncommitted;
--開啟事務
start transaction;
--查詢A賬戶中現有的錢,轉到B視窗進行操作
update account set money = money -100 where name = 'a';
update account set money = money +100 where name = 'b';
-- 轉到B視窗進行操作
- B視窗
--設定B使用者的資料庫隔離級别為Read uncommitted(讀未送出)
set transaction isolation level Read uncommitted;
--開啟事務
start transaction;
--查詢工資表,這時候B讀到了A未送出的資料(髒讀)
select * from account;
3.2.4.Read committed
當把事務的隔離級别設定為read committed時,會引發不可重複讀和虛讀,但避免了髒讀
- A視窗
set transaction isolation level Read committed;
start transaction;
--發現a帳戶是1000元,轉到b視窗
select * from account;
--發現a帳戶多了100,這時候,a讀到了别的事務送出的資料,兩次讀取a帳戶讀到的是不同的結果(不可重複讀)
select * from account;
- B視窗
set transaction isolation level Read committed;
start transaction;
update account set money=money+100 where name='A';
commit;--轉到a視窗
3.2.5.Repeatable read
當把事務的隔離級别設定為repeatable read(mysql預設級别)時,會引發虛讀,但避免了髒讀、不可重複讀。
- A視窗
set transaction isolation level repeatable read;
start transaction;
select * from account;--發現表有3個記錄,轉到b視窗
select * from account;--可能發現表有4條記錄,這時候發生了a讀取到另外一個事務插入的資料(虛讀)
- B視窗
start transaction;
insert into account(name,money) values('ggg',1000);
commit;--轉到a視窗
注意:mysql對虛讀已經進行了優化處理。是以展示不出虛讀的發生。
3.2.6.Serializable
- A視窗
set transaction isolation level Serializable;
start transaction;
select * from account;--轉到b視窗
- B視窗
set transaction isolation level Serializable;
start transaction;
--發現不能插入,隻能等待a結束事務才能插入
insert into account(name,money) values('ggg',1000);
3.3.小結
-
性能比較
Serializable 性能最差:事務一個一個執行的。排隊。
Serializable < Repeatable read < Read committed < Read uncommitted
-
安全性比較
Serializable 安全性最好:所有問題避免掉。
Serializable > Repeatable read > Read committed > Read uncommitted
mysql (預設)-- Repeatable read;
oracle(預設) – Read committed;