天天看點

JDBC專題(七)-事務的隔離級别

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語句如下所示

JDBC專題(七)-事務的隔離級别
髒讀最嚴重的事情、讀取資料是不真實的
2.1.2.不可重複讀

一個事務讀取另外一個送出過的資料。造成另外一個事務,多次讀取的内容不一緻,資料的内容的改變。—update

一個事務,讀取了另外一個事務送出了的資料。-----同一行資料。

資料的改變。—update

JDBC專題(七)-事務的隔離級别
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(串行化):可避免髒讀、不可重複讀、幻讀情況的發生。

不同的隔離級别對并發問題的解決情況如圖:

JDBC專題(七)-事務的隔離級别
注意:事務的隔離級别和資料庫并發性是成反比的,隔離級别越高,并發性越低。

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;