事務的4個特性(ACID)
- 原子性 Atomicity,每個事務中的操作,要么都成功,要么都失敗
- 一致性 Consistency,事務執行前后,資料庫中的資料應該保持一致
- 隔離性 Isolation,事務之間應該是隔離的,事務之間互不影響、干擾
- 持久性 Durability,事務一旦提交,便會將修改持久化到資料庫
事務管理的相關命令
start transaction; #開始事務
sql陳述句1;
sql陳述句2;
.....
commit; #提交事務
#rollback; #回滾
流程示例
start transaction;
insert into tb_user (name,age) values ('zhangsan',20); #顯示Query OK,這條sql陳述句可以成功執行
insert into tb_user (name,age) values ('李四','age'); #顯示ERROR,發生錯誤,只是說這條陳述句執行錯誤,但后面還可以執行sql陳述句
insert into tb_user (name,age) values ('wangwu',20); #顯示Query OK,
如果此時commit;提交,會把執行成功的2個sql陳述句做的修改持久化資料庫,失敗的sql陳述句則忽略,
其實發生ERROR時,為了做到事務的原子性,就應該rollback;回滾,

并不是說start transaction; ..... commit; 會自動維持事務的4個特性,全部成功就持久化到資料庫,某些sql陳述句發生錯誤,就自動回滾,不是這樣的,
事務的4個特性需要我們自己來維持,
代碼中使用事務也一樣:
...... //開啟事務
try{
..... //要執行的多條sql陳述句
commit; //若前面都正常執行,則提交
}catch(Exception e){
rollback; //發生錯誤就回滾
}
先開啟事務,把要執行的多個sql陳述句放到try中,都正確執行那就提交,發生錯誤就回滾,
catch就是對例外的處理,既然捕獲了例外進行了處理,就不會往上一級拋了,
如果每一級都是throws往上拋,拋到JVM,JVM默認的例外處理方式是:列印例外資訊,終止程式運行,
比如說下面這段代碼:
System.out.println(1); try{ System.out.println(1/0); }catch (Exception e){ System.out.println("error"); } System.out.println(2);
1 error 2
并不會自動在控制臺列印例外資訊,終止程式,
要看例外資訊,可以在catch中 System.out.println(e.getMessage()); 列印出來
事務的并發
事務的并發即同時執行多個事務,主要涉及事務的隔離性、隔離級別,
1、事務并發執行可能出現的問題
(1)臟讀 一個事務讀取其它事務尚未提交的資料
事務B對資料庫做了修改(執行成功但尚未提交),事務A讀取這些已修改的記錄,A讀取之后,B進行了回滾,A讀取到的資料變成了臟資料、無效資料,即臟讀,
隔離級別 Read commited 已提交讀,可解決臟讀問題,等到使用這些記錄的事務提交后才讀取資料,
(2)不可重復讀 前后多次讀取,讀取的資料內容不一致(期間進行了update操作)
比如說我卡里有2000,打算在ATM上取款2000,輸入取款金額2000點擊確定,系統查詢賬戶余額,還有2000,是夠的;
我老婆的微信系結了我的卡,這時把我卡里的1000給花了,賬戶余額為1000
ATM執行扣款-2000(在賬戶余額的基礎上扣,money-2000,又要獲取賬戶余額),并往外吐錢2000,1000-2000=-1000
ATM前后2次讀取余額(同一條記錄的資料),讀取的資料內容不一致,這就出現問題了,
隔離級別 Repeatable read 重復讀,可解決不可重復讀的問題,當有事務讀了某些行的資料后,這些行會被鎖住,不允許其它事務對這些行進行修改,這樣重復讀取到的資料就是一致的,
因為使用某些行時,這些行會被鎖定,其它事務不能讀取這些(可能會被修改的)行,也避免了臟讀問題,
(3)幻讀(虛讀) 前后多次讀取,讀取的記錄數不一致(期間進行了insert、delete操作)
隔離級別 Serializable 可解決幻讀問題,不允許事務并發,最安全,但性能最差,基本不用,
以上3個是讀問題,還可能產生一個寫問題:丟失更新,
(4)丟失更新 丟失更新是不可重復讀中的一種特殊情況,2個事務都要修改記錄內容(update),后提交的覆寫了前面提交的
| 時間 | 取款事務 | 支票轉賬事務 |
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為1000元 | |
| T4 | 查詢賬戶余額為1000元 | |
| T5 | 取出100,把存款余額改為900元 | |
| T6 | 提交事務 | |
| T7 | 匯入100元,把存款余額改為1100元 | |
| T8 | 提交事務 |
-100的更新操作丟失了,
2、4種隔離級別
- Read uncommitted:未提交讀,解決不了任何讀問題,安全性最低,但事務執行效率最高
- Read committed:已提交讀,解決了臟讀,但不可重復讀、虛讀有可能發生,oracle默認值,
- Repeatable read:重復度,解決了臟讀、不可重復讀,但虛讀有可能發生,mysql默認值,
- Serializable:串行化,不允許事務并發,可解決所有并發問題,安全性最高,但事務執行效率最低
一般折中選擇第2、3項,使用默認的即可,不必進行設定,
3、查看、設定隔離級別
#mysql 5
select @@tx_isolation; #查看當前會話使用的隔離級別
select @@global.tx_isolation; #查看全域設定的隔離級別
#mysql 8
select @@transaction_isolation; #查看當前會話使用的隔離級別
select @@global.transaction_isolation; #查看全域設定的隔離級別
#mysql5、mysql8的查看方式不同,5是tx,8是transaction,如果不對應會報錯Unknown system variable 'tx_isolation'|'transaction_isolation'
#設定事務的隔離級別,5、8一樣
set session transaction isolation level repeatable read; #設定當期會話使用的隔離級別為repeatable read
set global transaction isolation level repeatable read; #設定全域使用的隔離級別是repeatable read
如果我們沒有使用start transaction開啟事務,默認把一條sql陳述句(帶分號)作為一個事務處理,會自動提交,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/72678.html
標籤:MySQL
上一篇:MYSQL基礎陳述句(自我記憶)
下一篇:MySQL 視圖
