1、事務隔離級别
事務有四大特性:原子性、一緻性、隔離性、持久性。其中事務的隔離比較重要,事務隔離性處理在資料并發量較大的系統顯得比較重要。
資料庫在事務隔離這塊提供了四種事務隔離級别,分别是:讀取未送出内容(Read Uncommitted),讀取已送出内容(Read Committed),可重讀(Repeatable Read),串行化(serializable)。
不同的資料庫關于事務隔離的預設級别不同,Oracle資料庫預設的隔離級别為Read Committed, MySql的預設隔離之别則為Repeatable Read;
2、事務隔離級别對應産生的問題
為什麼不同的資料庫采用了不同的預設隔離級别?因為不同的隔離級别在并發操作資料庫時會産生不同的問題。 也就是由隔離級出現對應的問題:髒讀、不可重複讀及幻讀。
先了解這幾個問題的概念及産生。引用自:MySql事務隔離詳解
(1) 髒讀:在事務并發處理過程中,某一事務讀取了另一個事務未送出的資料。如事務A讀取到了事務B修改過的資料,但事務B未進行送出。
時間點 | 事務A | 事務B |
1 | select t.money from t_account t where t.name='scl' | |
2 | update t_account t set t.money = t.money+1000 where t.name = 'scl' | |
3 | select t.money from t_account t where t.name = 'scl' | |
4 | commit |
假如 在兩事務A、B 都未執行前,scl賬号有1000元, 在事務開始後,如果事務A第一次讀取到的資料為1000,第二次讀到的資料為2000。那麼這就出現了髒讀。因為在兩個不同僚務裡面應該是互相獨立的。不應該讀到其他事務的資料。
(2) 不可重複讀:在事務并發處理過程中,事務A在某時間點1内讀到的資料跟時間點2讀到的資料不一緻。跟髒讀的差別是,事務A先進行查詢,然後事務B送出了某一行記錄的修改,事務A再次查詢資料發現兩次讀出來的資料不一緻。(事務A讀取了事務B送出的内容,兩次查詢某一行或幾行資料内容不一緻)
commit; | ||
select t.money from t_account t where t.name = 'scl' |
假如 在兩事務A、B 都未執行前,scl賬号有1000元, 在事務開始後,如果事務A第一次讀取到的資料為1000,第二次讀到的資料為2000。那麼這就出現了不可重複讀。因為在 兩個不同僚務裡面應該是互相獨立的。A讀到了B送出的事務,導緻兩次讀取結果内容不一緻。
(3) 幻讀:某事務A進行a表資料查詢,然後事務B在a表内插入了一些新資料并且送出,事務A兩次查詢的資料條數存在差異。 與不可重複讀得差別是資料條數增加了。
select * from t_account t | ||
insert into t_account values ("1000","張三",2000); insert into t_account values ("1000","李四",3000); insert into t_account values ("1000","王五",4000); insert into t_account values ("1000","錢六",6000); | ||
假如 在兩事務A、B 都未執行前,使用sql:select * from t_account 傳回的是3條資料,在兩事務開啟後,事務A第一次讀取到3條資料,在事務B送出後,事務A讀取到了7條資料,那麼久出現了幻讀現象。
3、事務隔離級别應對事務并發産生的問題
既然事務隔離級别不同會導緻事務并發産生問題,那麼四個事務隔離級别分别會産生什麼問題?在開發時應選擇什麼哪個隔離級别方式?
隔離級别 | 髒讀 | 不可重複讀 | 幻讀 |
讀取未送出内容(Read Uncommitted) | √ | √ | √ |
讀取已送出内容(Read Committed) | X | ||
可重讀(Repeatable Read) | X | ||
串行化(serializable) | X |
可重讀這個隔離級别有可能會出現幻讀,有可能不出現。取決于資料庫當時的實作。
4、事務隔離級别的查詢與修改
Mysql事務隔離有全局事務,會話事務之分。可以通過以下指令查詢Mysql裡面事務的隔離級别:
1.SELECT @@global.tx_isolation;
2.SELECT @@session.tx_isolation;
3.SELECT @@tx_isolation;
session 指的是目前連接配接的事務級别,global則是全局的隔離級别。應該使用gobal來設定全局事務隔離級别。并進行相關的測試。
修改事務隔離級别使用指令:set tx_isolation='read-committed';
或者完整的事務隔離更改方法: set global transaction isolation level READ COMMITTED;
需要注意的是:即使使用了全局事務隔離級别設定,但開啟的視窗可能有session級别的緩存,把查詢視窗關閉再進行一次查詢即可确認事務級别是 否正确修改。(在64位Mysql5.5下測試過,無法在已開視窗下正确查詢事務隔離級别)
以上為本人對Mysql事務隔離級别的學習總結,如有錯誤,煩請指出糾正。