mysql相關事務的介紹以及應用
一、mysql相關知識準備
1.1、mysql事務
事務是一組不可分割的mysql語句組,這些語句組要麼全部執行成功,要麼全部執行失敗。
事務的四大特性(ACID)
1.原子性(atomicity):一個事務必須視為一個不可分割的最小工作單元,整個事務中的所有操作要麼全部提交成功,
要麼全部失敗回滾,對於一個事務來說,不可能只執行其中的一部分操作,這就是事務的原子性。
2.一致性(consistency):資料庫總數從一個一致性的狀態轉換到另一個一致性的狀態。
3.隔離性(isolation):一個事務所做的修改在最終提交以前,對其他事務是不可見的。
4.永續性(durability):一旦事務提交,則其所做的修改就會永久儲存到資料庫中。此時即使系統崩潰,修改的資料也不會丟失。
1.2、mysql事務的相關操作
1、查詢當前會話的事務級別
select @@tx_isolation;
repeatable read(MySQL預設隔離級別)
2、查詢全域性會話的事務級別
select @@global.tx_isolation
repeatable read(MySQL預設隔離級別)
3、 設定事務的mysql語法
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
4、設定當前會話的事務隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
當前會話結束後事務的隔離級別又會恢復原樣
5、設定全域性的事務隔離級別
SET GLOBALTRANSACTION ISOLATION LEVEL READ UNCOMMITTED
全域性設定後會保持不變,除非進行更改
6、mysql事務的提交方式
1、檢視預設的事務提交方式
#查詢事務的提交方式(當前會話的 0表示關閉自動提交,1表示開啟自動提交(預設情況下))
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
2、設定事務的提交方式 關閉自動提交
SET autocommit=0;
二、mysql中事務的隔離級別
2.0、演示準備
建立表來演示不同隔離級別下的髒讀,不可重複讀,幻讀等現象發生準備
建表sql
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` varchar(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`weath` float(20,0) DEFAULT NULL COMMENT '擁有的財富',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'xieqx', '1000');
INSERT INTO `user` VALUES ('2', 'xush', '1000');
INSERT INTO `user` VALUES ('3', 'lidn', '1000');
INSERT INTO `user` VALUES ('5', 'Bob', '1000');
建立多個事務(至少兩個進行處理)並設定對應的不同隔離級別來進行演示
關閉事務的自動提交
2.1、read uncommitted
- 一個事務中可以看到另一個是事務中未提交的資料(髒讀)
#設定事務的隔離級別 為未提交讀(會發生髒讀,不可重複讀,和幻讀現象)
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
2、演示髒讀場景。公司發工資 開啟兩個事務 事務A表示公司 事務B表示個人金額賬戶
注意場景下 兩個事務的開啟時間需要一致(或者另一個事務開啟要在一個事務在處理 增刪改的操作之前開啟),因為事務的處理本身就是在並行操作的場景演示(兩者同時操作一條記錄(競爭資源)) 否則無法實現 切記切記
事務A操作:
#開啟事務
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#查詢當前個人賬號金額 10
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 10 |
+----+-------+-------+
1 row in set (0.00 sec)
//更新個人賬戶金額 新增1000
mysql> update user set weath = weath + 9000 where id = "1";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#查詢金額更新成功
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 9010 |
+----+-------+-------+
##注意此時當前事務還沒有結束
事務B操作:
#個人查詢賬號操作
#開啟事務
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#查詢訂單(公司為更新操作之前)
mysql> select * from user where id ="1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 10 |
+----+-------+-------+
1 row in set (0.00 sec)
#再次查詢 查詢到了另一個事務中未提交的資料 造成了髒讀現象
mysql> select * from user where id ="1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 9010 |
+----+-------+-------+
1 row in set (0.00 sec)
2.2、read committed
1、一個事務A中讀取另一個事務B中已經提交的資料。但是另一個事務B中突然回滾,事務A再次讀取和原來不一樣的資料,所以可能造成多次讀取的資料結果不一致(不可重複讀,幻讀)。
#設定mysql的事務隔離級別 為已經提交讀
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
2、演示不可重複讀場景 公司發工資,但是客戶在同一個事務中獲取到兩個不同的金額
事務A操作
#開始事務
mysql> select * from user where id ="1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 10 |
+----+-------+-------+
1 row in set (0.00 sec)
#更新 金額
mysql> update user set weath = weath + 9000 where id = "1";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#執行提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
事務B操作:
#個人操作
#在個人事務中
#先進行查詢
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 10 |
+----+-------+-------+
1 row in set (0.00 sec)
#公司事務中進行了更新,但是沒有提交 查詢的結果保持不變 說明在該隔離級別下 避免了髒讀現象的發生
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 10 |
+----+-------+-------+
1 row in set (0.00 sec)
#公司的事務已經提交 ,但是還是在個人事務中,查詢出來兩種截然不同的金額結果 不可重複讀的現象發生了
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 9010 |
+----+-------+-------+
1 row in set (0.00 sec)
2.3、repeatable read(MySQL預設隔離級別)
1、 可以重複讀取,但有幻讀。讀寫觀點:讀取的資料行不可寫,但是可以往表中新增資料。在MySQL中,其他事務新增的資料,看不到,不會產生幻讀。採用多版本併發控制(MVCC)機制解決幻讀問題。
#可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,
#InnoDB預設級別。在#SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
mysql> SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
2、幻讀場景的演示
事務A操作:
#開啟事務
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#查詢目前的金額
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 20010 |
+----+-------+-------+
#更新金額
mysql> update user set weath=weath+10000 where id = "1";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#再次查詢
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 30010 |
+----+-------+-------+
#提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
事務B操作:
#開啟事務
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#A事務 更新金額但是沒有進行事務提交 (查詢出來原來的結果)
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 20010 |
+----+-------+-------+
1 row in set (0.00 sec)
#A事務提交後,還是在一個B事務中查詢金額 和上面的查詢保持不變 避免了不可重複讀操作
mysql> select * from user where id = "1";
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 20010 |
+----+-------+-------+
幻讀發生
事務A
#開啟事務
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#查詢使用者 還有6條記錄 最高id 為8
mysql> select * from user;
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 30010 |
| 2 | xush | 10 |
| 3 | lidn | 10 |
| 5 | Bob | 10 |
| 7 | guoqi | 200 |
| 8 | aaa | 100 |
+----+-------+-------+
6 rows in set (0.00 sec)
#在該事務中新增一條記錄id為9
mysql> insert into user value("9","bbb",102);
Query OK, 1 row affected (0.00 sec)
#提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
事務B
#事務B操作
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#在事務B 新增一條記錄前查詢記錄數
mysql> select * from user;
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 30010 |
| 2 | xush | 10 |
| 3 | lidn | 10 |
| 5 | Bob | 10 |
| 7 | guoqi | 200 |
| 8 | aaa | 100 |
+----+-------+-------+
6 rows in set (0.00 sec)
#事務A新增一條記錄並提交後 查詢還是沒有變化
mysql> select * from user;
+----+-------+-------+
| id | name | weath |
+----+-------+-------+
| 1 | xieqx | 30010 |
| 2 | xush | 10 |
| 3 | lidn | 10 |
| 5 | Bob | 10 |
| 7 | guoqi | 200 |
| 8 | aaa | 100 |
+----+-------+-------+
6 rows in set (0.00 sec)
#重新再插入一條資料 發現這條資料id為9的資料已經插入了,命名沒有查到id為9的記錄,但是插入的時候
#出現記錄已經存在 出現了幻讀情況的發生
mysql> insert into user value("9","bbb","100");
ERROR 1062 (23000): Duplicate entry '8' for key 'PRIMARY'
#或者 更新資料id為9的資料 更新可以成功再次查詢會發現多了一條資料 (好像出現了幻覺)
mysql> update user set weath = 520 where id = 9;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#更新後(自己查詢不到的id)結果發現查詢出來了這條記錄
mysql> select * from user;
+----+--------+-------+
| id | name | weath |
+----+--------+-------+
| 1 | xieqx | 30010 |
| 2 | xush | 10 |
| 3 | lidn | 10 |
| 5 | Bob | 10 |
| 7 | guoqi | 200 |
| 8 | aaa | 100 |
| 9 | bbb | 102 |
+----+--------+-------+
7 rows in set (0.00 sec)
2.4、serializable
1、可讀,不可寫。像java中的鎖,寫資料必須等待另一個事務結束。
#設定事務的隔離級別為 串形化
mysql> SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set, 1 warning (0.00 sec)
2、所謂串形化,它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。通俗地講就是,假如兩個事務都操作到同一資料行,對於讀取操作相關的操作,所有的事務都可以獲取其中的共享鎖,但是針對其中的增刪改的操作只有一個事務會獲取其中的排他鎖,只有該事務提交後,才會釋放其中的鎖。避免了不可重複讀的操作。