01-TCL-事務的理解
阿新 • • 發佈:2021-08-01
1、什麼是事務Transaction
一個事務是一個完整的業務邏輯單元,不可分。
例如:銀行賬戶轉賬,從賬戶A轉賬1000元到賬戶B,需要執行兩條DML的update語句
update t_act set balance=balance-1000 where actno='act_A';
update t_act set balance=balance+1000 where actno='act_B';
--以上兩條DML語句必須同時成功,或者同時失敗,不能一條成功一條失敗。要保證這樣的要求需要使用資料庫的"事務機制"
注意:跟事務相關的語句只有DML語句,即update、delete和insert。原因是DML的執行都是和資料庫裡的資料相關的,事務的存在就是為了保證資料的完整性、合法性以及安全性。
現實中所有的業務需求都需要事務機制,即需要多條DML語句聯合完成,只需要一條是不可能的。
2、事務的特性
事務包括四大特性:ACID (Atomicity原子性 、Consistency一致性 、Isolation隔離性、 Durability耐久性)
A:原子性,事務是最小的工作單元,不可再分
C:一致性,事務必需保證多條DML語句同時成功或者失敗,資料庫被修改的資料前後要保證一致
I:隔離性,事務A與事務B具有隔離,跟Java中的多執行緒一樣
D:永續性,說的是最終資料必須持久化的儲存到硬碟檔案中,即commit提交,一個事務才算以成功結束,不可再回滾
3、事務之間的隔離性
事務隔離性存在隔離級別,理論上隔離級別有四級:
第一級別:可讀未提交(read uncommitted) 對方事務還未提交,我們當前事務可以讀取到對方未提交的資料; 該級別會出現髒讀現象(dirty read):表示讀到了髒的資料 第二級別:可讀已提交(read committed) 只有當對方事務提交資料之後,我方事務才可讀到,該級別解決了髒讀現象 存在的問題是:不可重複讀原先第一次讀到的資料,我方事務先讀取了硬碟檔案的原始資料,但是這個事務還沒結 束,之後對方事務提交了資料,我方事務的需求還需要再一次讀原先的資料,此時就無法讀到原先的資料,只能讀 到對方事務提交後的資料了,我方事務就沒法成功結束事務。 第三級別:可重複讀(repeatable read) 解決了不可重複讀的問題。永遠只讀我啟動事務時的那份資料 存在的問題是:讀取到的資料是幻象 第四級別:序列化讀/序列化讀 不允許事務併發,我這個事務開啟,其他事務就沒法啟動 解決了所有問題,但效率降低,需要事務排隊 Oracle的事務級別是:可讀已提交 MySQL的事務級別:可重複讀
4、演示事務
MySQL的事務預設情況下是自動提交的(自動提交就是每執行一條DML語句後自動commit)
如何關閉自動提交,在每次開始事務前執行(start transaction;)。
--演示
--1、建表
drop table if exists t_user2;
create table t_user2(
id int primary key auto_increment,
username varchar(255)
);
--2、演示MySQL自動commit
mysql> insert into t_user2(username) values('zhangsan');
Query OK, 1 row affected (1.89 sec)
mysql> select * from t_user2;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user2;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
--通過上面操作可以看出rollback回滾失敗,自動提交了
--3、演示每次事務前關閉自動提交機制(注意每次事務都要關才行)
mysql> start transaction;--表示手動開啟事務,需要手動提交事務,相當於關閉自動提交。關掉一次只針對一次事務
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user2(username) values('lisi');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t_user2;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
| 2 | lisi |
+----+----------+
2 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.13 sec)
mysql> select * from t_user2;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
--------------------------------------------------------------
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user2(username) values('lisi');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_user2(username) values('wangwu');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_user2(username) values('zhaoliu');
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.13 sec)
mysql> select * from t_user2;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
| 3 | lisi |
| 4 | wangwu |
| 5 | zhaoliu |
+----+----------+
4 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user2;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
| 3 | lisi |
| 4 | wangwu |
| 5 | zhaoliu |
+----+----------+
4 rows in set (0.00 sec)
--每次關閉自動提交後只要執行了commit或rollback說明一個事務結束了,下一次在執行DML語句即開始事務不希望自動提交還得再關掉這個機制,可以看到id主鍵欄位即使原先的資料沒了,用過的主鍵值不再重複出現,但這沒有影響的,不用糾結
5、隔離級別演示
設定事務的全域性隔離級別:
set global transaction isolation level 隔離級別(包括read uncommitted、read committed、repeatable read和serializable)
檢視事務的全域性隔離級別:
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)