事務隔離級別

數據庫的事務有原子性,一致性,隔離性,持久性。

事務的隔離性由隔離級別體現,事務有四種隔離級別。

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級別下開銷最大,會對所有查詢加共享鎖,即使數據不存在。達到命令一條一條執行。


分享到:


相關文章: