數據庫的事務有原子性,一致性,隔離性,持久性。
事務的隔離性由隔離級別體現,事務有四種隔離級別。
1,READ UNCOMMITTED(未提交讀)
事務可以讀取其他事務未提交的修改。
2,READ COMMITTED(已提交讀)
事務讀取的信息是其他事務已提交的。
3:REPEATABLE READ(可重複讀)
與不可重複讀相對,事務中不存在讀取同一份數據不一樣的情況。READ UNCOMMITTED和READ COMMITTED級別下存在不可重複讀的情況,當事務還未提交,其他事務修改數據並且提交,此時該事務再查詢同一份數據時,數據發生改變。mysql的默認事務隔離級別。
4:SERIALIZABLE(串行化)
事務的讀取,修改,添加都是通過加鎖保證事務的執行次序。
<code>MariaDB> SELECT @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------/<code>
1:設置隔離級別為READ UNCOMMITTED
打開會話窗口一,設置事務隔離界別為“未提交讀”。
<code>MariaDB> set session transaction isolation level READ UNCOMMITTED;/<code>
再打開一個窗口二
<code>## 開啟事務
begin;
## 查詢信息
MariaDB> select account from zz_users limit 1;
+---------+
| account |
+---------+
| |
+---------+
1 rows in set (0.02 sec)
## 修改信息
MariaDB> update zz_users set account="lantian" where id=1;
Query OK, 1 rows affected (0.02 sec)/<code>
此時修改了數據,事務還未提交
回到原來窗口:
<code>## 開啟事務
begin;
## 查詢另一個會話事務修改的數據
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
| lantian |
+---------+
1 rows in set (0.02 sec)/<code>
此時查詢出了其他事務沒有提交的修改,此時二號窗口回滾。
<code>## 重新執行查詢
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
| |
+---------+
1 rows in set (0.01 sec)/<code>
會話一讀取了未生效的數據,也就是垃圾數據,對於會話一這就是髒讀。
2:設置隔離級別為READ COMMITTED
<code>MariaDB> set session transaction isolation level READ COMMITTED;/<code>
會話二重複上面的操作,會話一分別在會話二提交前和提交後查詢數據:
<code>## 會話二未提交
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
| |
+---------+
1 rows in set (0.01 sec)
## 會話二已提交
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
| lantian |
+---------+
1 rows in set (0.01 sec)/<code>
會話一讀取的信息是其他事務提交的數據,此時髒讀不存在。不可重複讀會存在,
刪除id為1 的數據,兩個會話重新開啟事務。
<code>## 會話一查詢id為2的數據
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account | id |
+----------+----+
| 88888888 | 2 |
+----------+----+
1 rows in set (0.01 sec)/<code>
<code>## 會話二插入一條數據
MariaDB> insert into zz_users (uuid, account, id) values ("uuid74298d2a3938ccb2d28067fe5817db77","666666", 1);
Query OK, 1 rows affected (0.01 sec)
MariaDB> select account,id from zz_users where id=1;
+---------+----+
| account | id |
+---------+----+
| 666666 | 1 |
+---------+----+
1 rows in set (0.01 sec)
MariaDB> commit;
Query OK, 0 rows affected (0.02 sec)/<code>
<code>## 會話一重新查詢數據發生變化
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account | id |
+----------+----+
| 77777777 | 2 |
+----------+----+
1 rows in set (0.01 sec)/<code>
同一份數據在同一個事務兩次讀取不一致,就是不可重複讀。
3:事務級別設置為REPEATABLE READ:
<code>## 會話一查詢數據
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account | id |
+----------+----+
| 77777777 | 2 |
+----------+----+
1 rows in set (0.01 sec)/<code>
<code>## 會話二更新數據操作
MariaDB> update zz_users set account="88888888" where id=2;
Query OK, 1 rows affected (0.01 sec)
MariaDB> commit;
Query OK, 0 rows affected (0.01 sec)/<code>
<code>## 會話一再次查詢數據
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account | id |
+----------+----+
| 77777777 | 2 |
+----------+----+
1 rows in set (0.01 sec)
## 提交事務
MariaDB> commit;
Query OK, 0 rows affected (0.01 sec)
## 再次查詢
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account | id |
+----------+----+
| 88888888 | 2 |
+----------+----+
1 rows in set (0.02 sec)/<code>
此時事務為結束之前,多次讀取數據都是一致的。不可重複讀不存在,但是幻讀會存在。
兩個會話重新開啟事務:
<code>## 會話一查詢id為1,2的數據。此時只存在id為2 的數據
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account | id |
+----------+----+
| 88888888 | 2 |
+----------+----+
1 rows in set (0.02 sec)/<code>
<code>## 會話2插入一條數據id為1
MariaDB> insert into zz_users (uuid, account, id) values ("uuid74298d2a3938ccb2d28067fe5817db79","666666", 1);
Query OK, 1 rows affected (0.01 sec)
## 查詢
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account | id |
+----------+----+
| 666666 | 1 |
| 88888888 | 2 |
+----------+----+
2 rows in set (0.02 sec)
## 提交數據
MariaDB> commit;
Query OK, 0 rows affected (0.01 sec)/<code>
<code>### 會話一再次查詢id為1,2的數據
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account | id |
+----------+----+
| 88888888 | 2 |
+----------+----+
1 rows in set (0.01 sec)
### 沒有id為1的數據,但是此時插入數據時
MariaDB> insert into zz_users (uuid, account, id) values ("uuid74298d2a3938ccb2d28067fe5817db79","666666", 1);
Duplicate entry '1' for key 'PRIMARY'
/<code>
此時沒有出現幻讀,讀取數據還是以前查找的數據,只是插入的時候回報重複id的錯誤,網上其他資料RR級別是會出現幻讀的,但是實驗沒有,可能MariaDB最新版本解決了RR級別幻讀的問題。
4:事務級別設置為REPEATABLE SERIALIZABLE:
重複上面的操作,先在會話一查詢:
<code>### 會話一查詢數據
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account | id |
+----------+----+
| 88888888 | 2 |
+----------+----+
1 rows in set (0.03 sec)/<code>
<code>### 此時會話二插入數據,此時會話二進入等待狀態,等到會話1提交後才會繼續執行。
MariaDB> insert into zz_users (uuid, account, id)
values ("uuid74298d2a3938ccb2d28067fe5817db79","666666", 1);
/<code>
總結:事務的隔離性是數據庫mvcc和鎖的共同作用下實現。SERIALIZABLE級別下開銷最大,會對所有查詢加共享鎖,即使數據不存在。達到命令一條一條執行。
閱讀更多 不要tuofa的後端 的文章