再談事務

上一篇我們簡單瞭解了事務,這一篇咱們再深刻一下吧mysql

Ⅰ、事務隔離級別

事務一共有四種隔離級別sql

簡稱 全稱 -
ru read-uncommited 未提交讀
rc read-committed 提交讀
rr repeatable-read 可重複讀
srz serializable 可串行

從真正意義上來看只有srz達到真正隔離性的要求session

oracel、sqlserver默認rc,mysql默認rr(99.99%達到隔離性要求)併發

事務隔離級別越低,事務請求的鎖越少或者保持鎖的時間就越短mvc

1.1 四種隔離級別解讀

事務隔離級別解決了三個問題,髒讀,不可重複讀,幻讀sqlserver

①read-uncommitted性能

能夠讀到其餘線程未提交的數據,沒人用,這就是髒讀spa

②read-committed線程

解決了髒讀,不會讀到其餘線程未提交的數據rest

可是a線程事務開始沒提交,b線程讀不到對應的數據,a線程事務提交後,b讀到了

這就是不可重複讀,兩次讀到不同,破壞了隔離性,一個線程的事務所作的修改被另外一個線程可見了

③repeatable-read

解決不可重複讀,一邊提交了,另外一邊仍是看不到,兩次讀結果同樣

重複讀還能夠解決一個問題,幻讀(讀到以前不存在的記錄,講鎖的時候再演示)

例外狀況:

  • for update鎖定讀就能夠讀到第一個線程中事務提交的數據,能夠說是幻讀,也能夠說是一個不可重複讀,這就是99.999%,哈哈
  • 這裏也是一種不符合隔離性的,讀到了以前不存在的記錄,只要是支持mvcc就很難作到徹底隔離性

④serializable

兩階段加鎖可串行化保證隔離性:加鎖階段,只加鎖不放鎖,解鎖階段,只放鎖,不解鎖

對於全部的寫,每行上面都有鎖,會有大量的鎖競爭和超時

這樣就失去了MVCC特性(非鎖定一致性讀)

全部操做都要加共享鎖,lock in share mode ,執行selct * from xxx;

其實重寫爲select * from xxx lock in share mode; 對這條記錄加共享鎖,

強制事務排序,使得不會互相沖突,這樣就不存在併發問題,都是串行了,讀寫相互阻塞

1.2 好奇心,咱們對比下rr和sr

RR隔離級別
sesion1:
mysql> set tx_isolation="REPEATABLE-READ";
Query OK, 0 rows affected (0.00 sec)

mysql> create table t_lock(a int, b int, primary key(a));
Query OK, 0 rows affected (0.11 sec)

mysql> insert into t_lock values(1,1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t_lock;
+---+------+
| a | b    |
+---+------+
| 1 |    1 |
+---+------+
1 row in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.02 sec)

mysql> select b from t_lock where a=1;
+------+
| b    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

session2:
mysql> set tx_isolation="REPEATABLE-READ";
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update  t_lock set b=2 where a = 1;
Query OK, 1 row affected (0.00 sec) Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.03 sec)

session1:
mysql> select b from t_lock where a=1;  -- 再執行一次,獲得的結果是1
+------+
| b    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> select b from t_lock where a=1 for update;  -- for update的去讀,獲得的結果是2
+------+
| b    |
+------+
|    2 |
+------+ 1 row in set (0.00 sec)
session1中, RR隔離級別下,前兩次讀都是讀取的快照,最後一次讀取的當前更新的值


SR隔離級別
session1:
mysql> select * from t_lock;
+---+------+
| a | b    |
+---+------+
| 1 |    1 |
+---+------+
1 row in set (0.00 sec)

mysql> set tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select b from t_lock where a=1;
+------+
| b    |
+------+
|    1 |
+------+ 1
row in set (0.00 sec)

session2:
mysql> show engine innodb status\G
-- ------------省略部分輸出------------
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 3, OS thread handle 0x7f946bc94700, query id 30 localhost root cleaning up
TABLE LOCK table `burn_test`.`t_lock` trx id 5390 lock mode IS
RECORD LOCKS space id 15 page no 3 n bits 72 index `PRIMARY` of table `burn_test`.`t_lock` trx id 5390 lock mode S locks rec but not gap  -- 有S鎖
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc     ;;
1: len 6; hex 00000000150c; asc       ;;
2: len 7; hex 8c000000340110; asc     4  ;;
3: len 4; hex 80000001; asc     ;;

mysql> set tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t_lock set b=2 where a=1;  -- 在SR的隔離級別下,直接阻塞,由於a=1上有一個S鎖
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

SERIALIZABLE的隔離級別通常來講是不會去用

1.3 事務隔離級別的選擇

show variables like 'tx_isolation';
set global 後只對以後建立的session生效,以前的session沒用

如何查看當前各個線程的事務隔離級別,sys庫裏面的session表看不了啊?

應該看performance_schema中user_variables_by_thread表

select * from user_variables_by_thread where variable_name = 'tx_isolation';
找到thread_id
select processlist_id from threads where thread_id in(xxx);
再對應到processlist id

重點:

  • 咱們生產中必定要用rc,不要用默認的rr,通常場景rc性能會好不少,rc的鎖好理解
  • 爲了同步數據一致性binlog_format用row,mixed會遇到各類bug致使主從不一致,5.7官方默認用row了,沒有協商的餘地,組複製也必須用row(目前MySQL若啓用rc,無論binlog_format怎麼設置都會強行轉爲row)
transaction_isolation = read-committed
binlog_format = row
上面兩個必定要配到my.cnf中,沒有任何理由
  • 有一種狀況rr比rc好,條件是,應用偏讀,一個事務裏面有10個select,後面會提到,read_view的緣由
相關文章
相關標籤/搜索