mysql-事務-校驗不可重複讀和幻象讀
問題描述
爲了驗證mysql在默唸的隔離級別是不是解決了不可重複讀和幻象讀的問題
預備
- 不可重複讀: 事務A讀到了事務B已經提交的修改數據
- 幻象讀: 事務A讀到了事務B已經提交的新增數據
校驗
查看mysql數據庫默認隔離級別
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set
驗證是否解決不可重複讀
- 事務A查詢用戶金額,此時開啓事務B
- 事務B修改用戶的金額,並提交事務
- 查看事務A中是否讀取到事務B提交的修改
事務A | 事務B
mysql> start transaction; | mysql> start transaction;
Query OK, 0 rows affected | Query OK, 0 rows affected
|
mysql> select * from t_account; | mysql> select * from t_account;
+----+---------+--------+ | +----+---------+--------+
| id | user_id | amount | | | id | user_id | amount |
+----+---------+--------+ | +----+---------+--------+
| 1 | 1 | 23 | | | 1 | 1 | 23 |
+----+---------+--------+ | +----+---------+--------+
1 row in set | 1 row in set
|
| mysql> update t_account set amount=10 where user_id=1;
| Query OK, 1 row affected
| Rows matched: 1 Changed: 1 Warnings: 0
| mysql> select * from t_account;
| +----+---------+--------+
| | id | user_id | amount |
| +----+---------+--------+
| | 1 | 1 | 10 |
| +----+---------+--------+
| 1 row in set
| # 事務B提交修改
| mysql> commit;
| Query OK, 0 rows affected
mysql> select * from t_account; |
+----+---------+--------+ |
| id | user_id | amount | |
+----+---------+--------+ |
| 1 | 1 | 23 | |
+----+---------+--------+ |
1 row in set |
# 事務A也提交
mysql> commit;
Query OK, 0 rows affected
mysql> select * from t_account;
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 1 | 1 | 10 |
+----+---------+--------+
1 row in set
可以發現,直至事務B提交了事務,在事務A中,也沒有讀取到事務B修改的值。只有事務A也提交事務,才能查詢到修改的值,但這已經沒有事務了
驗證是否解決幻象讀
- 事務A查詢用戶金額,此時開啓事務B
- 事務B新增另一個用戶的帳戶,並提交事務
- 查看事務A中是否讀取到事務B提交的新增用戶的帳戶的數據
事務A | 事務B
mysql> start transaction; | mysql> start transaction;
Query OK, 0 rows affected | Query OK, 0 rows affected
|
mysql> select * from t_account; | mysql> select * from t_account;
+----+---------+--------+ | +----+---------+--------+
| id | user_id | amount | | | id | user_id | amount |
+----+---------+--------+ | +----+---------+--------+
| 1 | 1 | 10 | | | 1 | 1 | 10 |
+----+---------+--------+ | +----+---------+--------+
1 row in set | 1 row in set
|
| mysql> INSERT INTO `dbl`.`t_account` (`user_id`, `amount`)
| VALUES ('2', '8');
|
| Query OK, 1 row affected
| mysql> select * from t_account;
| +----+---------+--------+
| | id | user_id | amount |
| +----+---------+--------+
| | 1 | 1 | 10 |
| | 3 | 2 | 8 |
| +----+---------+--------+
| 2 rows in set
|
| mysql> commit;
| Query OK, 0 rows affected
mysql> select * from t_account; |
+----+---------+--------+ |
| id | user_id | amount | |
+----+---------+--------+ |
| 1 | 1 | 10 | |
+----+---------+--------+ |
1 row in set |
可以發現,直至事務B提交了事務,在事務A中,也沒有讀取到事務B新增的帳戶數據
結論
由上述驗證,發現,mysql默認的隔離級別(repeatable read)確實解決了不可重複讀和幻象讀的問題