上一篇我們簡單瞭解了事務,這一篇咱們再深刻一下吧mysql
事務一共有四種隔離級別sql
簡稱 | 全稱 | - |
---|---|---|
ru | read-uncommited | 未提交讀 |
rc | read-committed | 提交讀 |
rr | repeatable-read | 可重複讀 |
srz | serializable | 可串行 |
從真正意義上來看只有srz達到真正隔離性的要求session
oracel、sqlserver默認rc,mysql默認rr(99.99%達到隔離性要求)併發
事務隔離級別越低,事務請求的鎖越少或者保持鎖的時間就越短mvc
事務隔離級別解決了三個問題,髒讀,不可重複讀,幻讀sqlserver
①read-uncommitted性能
能夠讀到其餘線程未提交的數據,沒人用,這就是髒讀spa
②read-committed線程
解決了髒讀,不會讀到其餘線程未提交的數據rest
可是a線程事務開始沒提交,b線程讀不到對應的數據,a線程事務提交後,b讀到了
這就是不可重複讀,兩次讀到不同,破壞了隔離性,一個線程的事務所作的修改被另外一個線程可見了
③repeatable-read
解決不可重複讀,一邊提交了,另外一邊仍是看不到,兩次讀結果同樣
重複讀還能夠解決一個問題,幻讀(讀到以前不存在的記錄,講鎖的時候再演示)
例外狀況:
④serializable
兩階段加鎖可串行化保證隔離性:加鎖階段,只加鎖不放鎖,解鎖階段,只放鎖,不解鎖
對於全部的寫,每行上面都有鎖,會有大量的鎖競爭和超時
這樣就失去了MVCC特性(非鎖定一致性讀)
全部操做都要加共享鎖,lock in share mode ,執行selct * from xxx;
其實重寫爲select * from xxx lock in share mode; 對這條記錄加共享鎖,
強制事務排序,使得不會互相沖突,這樣就不存在併發問題,都是串行了,讀寫相互阻塞
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的隔離級別通常來講是不會去用
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
重點:
transaction_isolation = read-committed binlog_format = row 上面兩個必定要配到my.cnf中,沒有任何理由