MySQL RR隔離級別死鎖分析一例

2021-03-03 老葉茶館

問:為什麼在RC隔離級別下不會死鎖,RR隔離級別下卻發生死鎖了。

表結構及數據情況如下:

drop table tt;

CREATE TABLE `tt` (
 `id` int(11) NOT NULL,
 `c1` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `c1` (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into tt values(1,1);

事務&語句執行過程如下:
session 1session 2

begin;


select * from tt where c1=1 for update;


update tt set id=2 where c1=1;



begin;

select * from tt where c1=1 for update;

堵塞

select * from tt where c1=1 for update;



死鎖、回滾

一、分析 session 1 的第一個SQL:
select * from tt where c1=1 for update;

執行以上SQL後加鎖,詳細鎖信息分別如下:

---TRANSACTION 231106, ACTIVE 9 sec
3 lock struct(s), heap size 1160, 2 row lock(s)
MySQL thread id 11, OS thread handle 140737153623808, query id 303 localhost root
TABLE LOCK table `test`.`tt` trx id 231106 lock mode IX
RECORD LOCKS space id 127 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231106 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 127 page no 3 n bits 72 index PRIMARY of table `test`.`tt` trx id 231106 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
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 0000000386c0; asc       ;;
 2: len 7; hex aa0000003f0110; asc     ?  ;;
 3: len 4; hex 80000001; asc     ;;

---TRANSACTION 231105, ACTIVE 7 sec
3 lock struct(s), heap size 1160, 2 row lock(s)
MySQL thread id 11, OS thread handle 140737153623808, query id 295 localhost root
TABLE LOCK table `test`.`tt` trx id 231105 lock mode IX
RECORD LOCKS space id 127 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231105 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 127 page no 3 n bits 72 index PRIMARY of table `test`.`tt` trx id 231105 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
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 0000000386c0; asc       ;;
 2: len 7; hex aa0000003f0110; asc     ?  ;;
 3: len 4; hex 80000001; asc     ;;

因為c1是唯一鍵,因此加鎖方式不管怎麼樣都是LOCK_X|LOCK_REC_NOT_GAP。主鍵上也是同樣的,就是鎖住了二級唯一索引和主鍵的相關記錄。

二、分析session 1第二個SQL:
update tt set id=2 where c1=1;

執行以上SQL後加鎖的詳細信息如下:

     這一句比較重要。在二級唯一索引c1上會做一個刪除和插入操作,也就是會將原來的「1,1」記錄標記為del flag,同時插入「2,1」這條記錄,這會引起一個鎖的繼承操作(lock_rec_inherit_to_gap_if_gap_lock調用會出現GAP LOCK)。在此之前還會涉及到唯一性檢查,因此還有LOCK_S鎖和next key lock鎖的存在(對於二級索引做唯一性檢查始終是next key lock)。這裡的del flag也是形成死鎖的重要原因。
    對於二級索引的update操作總是先刪除然後插入記錄,主鍵則會進行判斷是否可以容下新的記錄。

-TRANSACTION 231106, ACTIVE 1626 sec
5 lock struct(s), heap size 1160, 5 row lock(s), uando log entries 2
MySQL thread id 11, OS thread handle 140737153623808, query id 305 localhost root
TABLE LOCK table `test`.`tt` trx id 231106 lock mode IX
RECORD LOCKS space id 127 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231106 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 127 page no 3 n bits 72 index PRIMARY of table `test`.`tt` trx id 231106 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 0000000386c2; asc       ;;
 2: len 7; hex 2c000000410dca; asc ,   A  ;;
 3: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 127 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231106 lock mode S(LOCK_S) locks gap and rec(LOCK_ORDINARY[next_key_lock])
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 127 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231106 lock mode S(LOCK_S) locks gap before rec(LOCK_GAP)
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000002; asc     ;;

5 lock struct(s), heap size 1160, 5 row lock(s), undo log entries 2
MySQL thread id 11, OS thread handle 140737153623808, query id 316 localhost root
TABLE LOCK table `test`.`tt` trx id 231123 lock mode IX
RECORD LOCKS space id 128 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231123 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 128 page no 3 n bits 72 index PRIMARY of table `test`.`tt` trx id 231123 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 0000000386d3; asc       ;;
 2: len 7; hex 370000003206e2; asc 7   2  ;;
 3: len 4; hex 80000001; asc     ;;

RECORD LOCKS space id 128 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231123 lock mode S(LOCK_S) locks gap and rec(LOCK_ORDINARY[next_key_lock])
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;RECORD LOCKS space id 128 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231123 lock mode S(LOCK_S) locks gap before rec(LOCK_GAP)
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000002; asc     ;;

到這裡為止,RR和RC隔離級別下,加鎖並沒有什麼不同,因為都是唯一值,同時鎖繼承也都是二級索引上的都是LOCK_S|LOCK_ORDINARY[next_key_lock],但是下面就會出現不同了。

三、分析session 2的第一個SQL:

注意這裡開始就出現不同了:

select * from tt where c1=1 for update;

實際上,執行以上SQL的時候,存在2條c1=1的記錄。雖然「1,1」標記為刪除了,但是「1,2」還沒有提交,但都是需要訪問的。

發生堵塞時,詳細信息如下:

LOCK WAIT 2 lock struct(s), heap size 1160, 1 row lock(s)
MySQL thread id 10, OS thread handle 140737153824512, query id 350 localhost root statistics
select * from tt where c1=1 for update
-- TRX HAS BEEN WAITING 11 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 129 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231146 lock_mode X(LOCK_X) locks gap and rec(LOCK_ORDINARY[next_key_lock]) waiting(LOCK_WAIT)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

LOCK WAIT 2 lock struct(s), heap size 1160, 1 row lock(s)
MySQL thread id 10, OS thread handle 140737153824512, query id 325 localhost root statistics
select * from tt where c1=1 for update
-- TRX HAS BEEN WAITING 9 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 128 page no 4 n bits 72 index c1 of table `test`.`tt` trx id 231128 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP) waiting(LOCK_WAIT)Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

我們這裡可以看到,對於RR隔離級別下唯一鍵c1的記錄「1,1」已經刪除了。經過debug發現這裡會在函數中row_search_mvcc加鎖前做判斷如下:

if (!set_also_gap_locks
           || srv_locks_unsafe_for_binlog
           || trx->isolation_level <= TRX_ISO_READ_COMMITTED
            || (unique_search && !rec_get_deleted_flag(rec, comp))
           || dict_index_is_spatial(index)) {

           goto no_gap_lock;
       } else {
           lock_type = LOCK_ORDINARY;
       }

拋開其他,來分析以下這兩句

(如果是RC模式,則直接上LOCK_REC_NOT_GAP,即只鎖住記錄本身)

(當不是RC隔離級別,
    如果是二級唯一索引並且沒有被標記為del flag,則標記為LOCK_REC_NOT_GAP;
    但如果標記為del flag了,則標記為LOCK_ORDINARY就是next key lock)

四、分析session 1的最後一個語句也就是產生死鎖的語句:
select * from tt where c1=1 for update;

如上,這個語句會訪問「1,1」(標記為刪除了)、「1,2」(沒有提交)這兩個記錄。這個時候就出現了不同。

只需要唯一索引 1,1上  LOCK_REC_NOT_GAP|LOCK_X 及記錄索引,這個鎖在本事物的第一句語句上已經獲得了,因此直接通過了,不需要做檢測。

需要在唯一索引「 1,1」上 LOCK_ORDINARY|LOCK_X 也就是next key lock。這個鎖在本事物中並沒有獲取過,因此需要重新的檢測所的兼容性,最終加入了等待列表。

我們來看一下函數lock_rec_lock_slow,做debug的時候明顯看到了不同的邏輯(原文基礎上加了中文注釋):

if (lock_rec_has_expl(mode, block, heap_no, trx)) {
        /* The trx already has a strong enough lock on rec: do
       nothing *///本例 對於RC會走這裡 注意這裡的英文解釋
       lock_rec_print(mode,block,heap_no,index,thr_get_trx(thr));
       err = DB_SUCCESS;
   } else {//對於RR走這裡


       const lock_t* wait_for = lock_rec_other_has_conflicting(
           mode, block, heap_no, trx,index);


        if (wait_for != NULL) {
           /* If another transaction has a non-gap conflicting
           request in the queue, as this transaction does not
           have a lock strong enough already granted on the
           record, we may have to wait. */
           RecLock rec_lock(thr, index, block, heap_no, mode);
           err = rec_lock.add_to_waitq(wait_for);
       }

最終在RR隔離級別下形成了環路,情況如下:

session1 首先獲得唯一索引上的「1,1」記錄的

LOCK_REC_NOT_GAP|LOCK_X

然後session 1做update 獲得唯一索引上的「1,1」記錄的 LOCK_ORDINARY(next key lock)|LOCK_S

session 2需要獲取唯一索引上的"1,1"記錄的 LOCK_ORDINARY(next key lock)|LOCK_X 發生等待

接著,session 1需要獲取唯一索引上的「1,1」記錄的 LOCK_ORDINARY(next key lock)|LOCK_X 加入等待隊列進行等待

如此死鎖發生了。而RC模式下最後兩步需要獲取的都是 LOCK_REC_NOT_GAP|LOCK_X,雖然session 2處於等待,但是session1因為已經獲得相同級別的鎖不會在進行檢測加鎖等待,而直接通過了。

下面是死鎖的詳細內容:

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 117 page no 4 n bits 72 index c1 of table `t1`.`tt` trx id 230530 lock_mode X(LOCK_X) locks gap and rec(LOCK_ORDINARY[next_key_lock]) waiting(LOCK_WAIT)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 230525, ACTIVE 68 sec starting index readmysql tables in use 1, locked 1
6 lock struct(s), heap size 1160, 6 row lock(s), undo log entries 2
MySQL thread id 6, OS thread handle 140737153423104, query id 156 localhost root statistics
select * from tt where c1=1 for update
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 117 page no 4 n bits 72 index c1 of table `t1`.`tt` trx id 230525 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 117 page no 4 n bits 72 index c1 of table `t1`.`tt` trx id 230525 lock_mode X(LOCK_X) locks gap and rec(LOCK_ORDINARY[next_key_lock]) waiting(LOCK_WAIT)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000001; asc     ;;

*** WE ROLL BACK TRANSACTION (1)

最後留下幾個棧幀以備分析使用

#0  lock_rec_set_nth_bit (lock=0x30b1230, i=3) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/include/lock0priv.ic:91
#1  0x0000000001a5d44a in RecLock::lock_alloc (trx=0x7fffd7803b10, index=0x7ffe7459ff80, mode=546, rec_id=..., size=9)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1484
#2  0x0000000001a5d826 in RecLock::create (this=0x7fffec0c0eb0, trx=0x7fffd7803b10, owns_trx_mutex=false, add_to_hash=true, prdt=0x0)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1537
#3  0x0000000001a5e60c in lock_rec_add_to_queue (type_mode=546, block=0x7fff9adb8150, heap_no=3, index=0x7ffe7459ff80, trx=0x7fffd7803b10,
    caller_owns_trx_mutex=false) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1853
#4  0x0000000001a611ec in lock_rec_inherit_to_gap_if_gap_lock (block=0x7fff9adb8150, heir_heap_no=3, heap_no=1)
    at /root/mysqlall/percona--locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:2829
#5  0x0000000001a62ea3 in lock_update_insert (block=0x7fff9adb8150, rec=0x7fff9b9c408c "\200")
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:3659
#6  0x0000000001c53c25 in btr_cur_optimistic_insert (flags=0, cursor=0x7fffec0c23f0, offsets=0x7fffec0c24c8, heap=0x7fffec0c13e0, entry=0x7ffe7403bb70,
   rec=0x7fffec0c24c0, big_rec=0x7fffec0c24b8, n_ext=0, thr=0x7ffe7403ba00, mtr=0x7fffec0c1bc0)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/btr/btr0cur.cc:3346
#7  0x0000000001b195fe in row_ins_sec_index_entry_low (flags=0, mode=2, index=0x7ffe7459ff80, offsets_heap=0x7ffe7403bf98, heap=0x7ffe7403c448, entry=0x7ffe7403bb70,
trx_id=0, thr=0x7ffe7403ba00, dup_chk_only=false) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0ins.cc:3166
#8  0x0000000001b1a15e in row_ins_sec_index_entry (index=0x7ffe7459ff80, entry=0x7ffe7403bb70, thr=0x7ffe7403ba00, dup_chk_only=false)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0ins.cc:3421
#9  0x0000000001b9e053 in row_upd_sec_index_entry (node=0x7ffe7403b6f8, thr=0x7ffe7403ba00)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0upd.cc:2337
#10 0x0000000001b9e1c3 in row_upd_sec_step (node=0x7ffe7403b6f8, thr=0x7ffe7403ba00)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0upd.cc:2364

#0  lock_rec_set_nth_bit (lock=0x30b28b8, i=2) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/include/lock0priv.ic:91
#1  0x0000000001a5d44a in RecLock::lock_alloc (trx=0x7fffd7804080, index=0x7ffe74064ea0, mode=259, rec_id=..., size=9)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1484
#2  0x0000000001a5d826 in RecLock::create (this=0x7fffec0c1e00, trx=0x7fffd7804080, owns_trx_mutex=true, add_to_hash=true, prdt=0x0)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1537
#3  0x0000000001a5e1c4 in RecLock::add_to_waitq (this=0x7fffec0c1e00, wait_for=0x30b0e58, prdt=0x0)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1731
#4  0x0000000001a5ee37 in lock_rec_lock_slow (impl=0, mode=3, block=0x7fff4d027b20, heap_no=2, index=0x7ffe74064ea0, thr=0x7ffe7459ff60)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:2004
#5  0x0000000001a5f1ce in lock_rec_lock (impl=false, mode=3, block=0x7fff4d027b20, heap_no=2, index=0x7ffe74064ea0, thr=0x7ffe7459ff60)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:2082
#6  0x0000000001a69a02 in lock_sec_rec_read_check_and_lock (flags=0, block=0x7fff4d027b20, rec=0x7fff4da8c07e "\200", index=0x7ffe74064ea0, offsets=0x7fffec0c2690,
    mode=LOCK_X, gap_mode=0, thr=0x7ffe7459ff60) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:6457
#7  0x0000000001b717f7 in sel_set_rec_lock (pcur=0x7ffe7459f6d0, rec=0x7fff4da8c07e "\200", index=0x7ffe74064ea0, offsets=0x7fffec0c2690, mode=3, type=0,    
thr=0x7ffe7459ff60, mtr=0x7fffec0c2180) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0sel.cc:1270
#8  0x0000000001b7ab6a in row_search_mvcc (buf=0x7ffe7405b9c0 "\375\002", mode=PAGE_CUR_GE, prebuilt=0x7ffe7459f4b0, match_mode=1, direction=0)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0sel.cc:5591

#0  lock_rec_lock_slow (impl=0, mode=1027, block=0x7fff3310cdf0, heap_no=2, index=0x7ffe74076d90, thr=0x7ffe7459fc20)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:1962
#1  0x0000000001a5f1ce in lock_rec_lock (impl=false, mode=1027, block=0x7fff3310cdf0, heap_no=2, index=0x7ffe74076d90, thr=0x7ffe7459fc20)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:2082
#2  0x0000000001a69a02 in lock_sec_rec_read_check_and_lock (flags=0, block=0x7fff3310cdf0, rec=0x7fff33bdc07e "\200", index=0x7ffe74076d90, offsets=0x7fffec0c2690,
    mode=LOCK_X, gap_mode=1024, thr=0x7ffe7459fc20) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:6457
#3  0x0000000001b717f7 in sel_set_rec_lock (pcur=0x7ffe7459f6d0, rec=0x7fff33bdc07e "\200", index=0x7ffe74076d90, offsets=0x7fffec0c2690, mode=3, type=1024,
    thr=0x7ffe7459fc20, mtr=0x7fffec0c2180) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0sel.cc:1270
#4  0x0000000001b7ab6a in row_search_mvcc (buf=0x7ffe7403ae80 "\375\002", mode=PAGE_CUR_GE, prebuilt=0x7ffe7459f4b0, match_mode=1, direction=0)
    at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/row/row0sel.cc:5591
#5  0x00000000019d5493 in ha_innobase::index_read (this=0x7ffe7403cda0, buf=0x7ffe7403ae80 "\375\002", key_ptr=0x7ffe74095600 "", key_len=5, 
    find_flag=HA_READ_KEY_EXACT) at /root/mysqlall/percona-server-locks-detail-5.7.22/storage/innobase/handler/ha_innodb.cc:9536
#6  0x0000000000f934aa in handler::index_read_map (this=0x7ffe7403cda0, buf=0x7ffe7403ae80 "\375\002", key=0x7ffe74095600 "", keypart_map=1, 
    find_flag=HA_READ_KEY_EXACT) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/handler.h:2942

       


知數堂

葉金榮與吳炳錫聯合打造

領跑IT精英培訓

行業資深專家強強聯合,傾心定製

MySQL的實戰/ MySQL的優化/ MongoDB的/

Python / SQL優化/ Hadoop + ELK

數門精品課程

「閱讀原文」可獲更多正課試聽視頻

密碼:hg3h

緊隨技術發展趨勢,定期優化培訓教案

融入大量生產案例,貼合企業一線需求

社群陪伴學習,一次報名,可學1年

DBA,開發工程師必修課

上千位學員已華麗轉身,薪資翻番,職位提升

改變已悄然發生,你還在等什麼?

MySQL的入門到精通-ZST

  (QQ群號:793818397)    


相關焦點

  • MySQL死鎖分析與解決之路
    從死鎖的定義來看,MySQL 出現死鎖的幾個要素為:a.兩個或者兩個以上事務b.每個事務都已經持有鎖並且申請新的鎖c.鎖資源同時只能被同一個事務持有或者不兼容d.事務之間因為持有鎖和申請鎖導致彼此循環等待說明:後續內容實驗環境為 5.7 版本,隔離級別為 RR(可重複讀)-- InnoDB 鎖類型--
  • 這有一把鑰匙,打開MySQL死鎖問題!
    3,如果死鎖會發生,該如何避免,mysql的事務自動會處理(有人說會自動處理),那我能不能代碼的設計上,避免這種死鎖的情況?1. 這種情況是有可能導致死鎖的,A在等待B釋放資源,B在等待A釋放資源,相互等待資源,造成死鎖。
  • Mysql資料庫update操作死鎖問題分析
    基於以上前提,我發現近期經常會報出一些資料庫操作失敗的錯誤,列印出mysql錯誤日誌如下:1213 Deadlock found when trying to get lock; try restarting transaction即觸發了mysql的死鎖錯誤。
  • MySQL REPLACE死鎖問題深入剖析
    姜承堯IT圈最會講故事的破產碼農上周五發布的MySQL ACE或許都說不清的死鎖問題一例,很多同學躍躍欲試想要嘗試年薪
  • MySQL 的加鎖處理分析
    同時,微博上也經常會收到MySQL鎖相關的私信,讓我幫助解決一些死鎖的問題。本文,準備就MySQL/InnoDB的加鎖問題,展開較為深入的分析與討論,主要是介紹一種思路,運用此思路,拿到任何一條SQL語句,都能完整的分析出這條語句會加什麼鎖?會有什麼樣的使用風險?甚至是分析線上的一個死鎖場景,了解死鎖產生的原因。MySQL是一個支持插件式存儲引擎的資料庫系統。
  • MySQL 加鎖處理分析
    組合一:id列是主鍵,RC隔離級別組合二:id列是二級唯一索引,RC隔離級別組合三:id列是二級非唯一索引,RC隔離級別組合四:id列上沒有索引,RC隔離級別組合五:id列是主鍵,RR隔離級別組合六:id列是二級唯一索引,RR隔離級別組合七:id列是二級非唯一索引,RR隔離級別組合八:id
  • 一個線上SQL死鎖異常分析:深入了解事務和鎖
    本文詳細介紹了和死鎖有關的知識點,通過深入分析MySQL事務和鎖的機制,結合案例背景,找到了問題的所在,並梳理了解決方案,詳解其原理。希望對同學們有所啟發。最近線上消費MetaQ的服務頻繁報SQL死鎖異常,雖然最終可以基於事務自動回滾和邏輯重試保證最終正確性,但若一直放任不管,海量報警日誌會掩蓋真正需要緊急處理的異常,同時頻繁回滾也會降低消費端的吞吐量。
  • MySQL的事務隔離級別是什麼?
    原子性Atomicity,事務是一個最小的執行單位,事務裡面的SQL要麼全執行,要麼全不執行,就拿A與B轉帳為例,一條語句從A裡扣錢,另一條語句往B身上加錢,如果這兩條語句不能全部執行,而是成功了一部分,那事務就沒有存在的意義了。隔離性Isolate,顧名思義就是將事務與另一個事務隔離開,為什麼要隔離呢?
  • MySQL 三萬字精華總結 + 面試100 問,吊打面試官綽綽有餘(收藏系列)
    事務隔離級別資料庫事務的隔離級別有4種,由低到高分別為READ-UNCOMMITTED(讀未提交): 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致髒讀、幻讀或不可重複讀。READ-COMMITTED(讀已提交): 允許讀取並發事務已經提交的數據,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生。
  • MySQL 工作、底層原理,看這一篇就夠了!
    它根據MySql AB公司提供的文件訪問層的一個抽象接口來定製一種文件訪問機制(這種訪問機制就叫存儲引擎)SQL 語句執行過程資料庫通常不會被直接使用,而是由其他程式語言通過SQL語句調用mysql,由mysql處理並返回執行結果。那麼Mysql接受到SQL語句後,又是如何處理?
  • 一文講清楚MySQL事務隔離級別和實現原理,開發人員必備知識點
    採用哪種隔離級別要根據系統需求權衡決定,其中,可重複讀是 MySQL 的默認級別。事務隔離其實就是為了解決上面提到的髒讀、不可重複讀、幻讀這幾個問題,下面展示了 4 種隔離級別對這三個問題的解決程度。只有串行化的隔離級別解決了全部這 3 個問題,其他的 3 個隔離級別都有缺陷。
  • 高性能MySQL學習總結一
    一、MySQL邏輯架構第一層的服務不是MySQL獨有的,大多數是基於網絡的客戶端/服務端的工具,如連接處理、授權認證、安全等等。第二層就是MySQL的核心功能,包括查詢解析、分析、優化、緩存以及所有的內置函數,所有的跨存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖等。
  • Mysql innodb 存儲引擎的性能優化
    這裡只是我對這個PDF文件進行了翻譯,由於本人剛從事mysql DBA一職,所以很多東西自己並不能很好的翻譯出來,其中對於硬體部分翻譯的應該還行
  • MySQL - percona-toolkit工具
    下載地址:https://www.percona.com/downloads/percona-toolkit/LATEST/工具分類開發類 pt-duplicate-key-checker 列出並刪除重複的索引和外鍵 pt-online-schema-change 在線修改表結構 pt-query-advisor 分析查詢語句
  • MySQL內存不釋放分析
    問題分析場景1 使用sysbench壓測資料庫場景2 load 一個很大事務的insert語句問題突破測試jemalloc場景1使用sysbench
  • 去 BAT 面試,總結了這 55 道 MySQL 面試題!
    8、請簡潔描述Mysql中InnoDB支持的四種事務隔離級別名稱,以及逐級之間的區別?SQL標準定義的四個隔離級別為:read uncommited :讀到未提交數據read committed:髒讀,不可重複讀repeatable read:可重讀serializable :串行事物
  • 幾個常見而嚴重的 MySQL 問題分析 | 運維進階
    本文將抽取幾個常見而嚴重的MySQL問題進行分析,並給出深度解答。藉以大家幫助思考。【作者】一力搜索,某銀行分布式資料庫架構師,重點負責行內分布式資料庫領域及私有雲,個人微信公眾號:一力搜索。對於引入MDL,其主要解決了2個問題,一個是事務隔離問題,比如在可重複讀隔離級別下,會話A在2次查詢期間,會話B對表結構做了修改,兩次查詢結果就會不一致,無法滿足可重複讀的要求;另外一個是數據複製的問題,比如會話A執行了多條更新語句期間,另外一個會話B做了表結構變更並且先提交,就會導致slave在重做時,先重做alter,再重做update時就會出現複製錯誤的現象。
  • 超全面MySQL語句加鎖分析(上篇)(求轉)
    普通的SELECT語句普通的SELECT語句在:READ UNCOMMITTED隔離級別下,不加鎖,直接讀取記錄的最新版本,可能發生髒讀、不可重複讀和幻讀問題。READ COMMITTED隔離級別下,不加鎖,在每次執行普通的SELECT語句時都會生成一個ReadView,這樣解決了髒讀問題,但沒有解決不可重複讀和幻讀問題。
  • 面試官:談談你對MySQL事務的認識?
    這篇文章屬於mysql資料庫系列,我們來談談事務方面的常見面試題。那麼,具體題目有下面這些:1、講講為什麼用事務?事務的四大特性?事務的隔離級別知道吧,你們生產用哪種?2、Innodb中ACID具體是如何實現的?3、redo log和binlog的一致性如何保證?4、大事務有哪些壞處?生產上遇到過大事務麼?你怎麼排查和解決的?