Fonte: conta pública yangyidba
I. Introdução
Deadlock é na verdade um problema técnico muito interessante e desafiador.Provavelmente, todo DBA e alguns desenvolvedores o encontrarão no processo de trabalho. Com relação ao impasse, continuarei a escrever uma série de estudos de caso, na esperança de ajudar amigos que desejam entender o impasse.
Análise de dois casos
2.1 Cenário de negócios
A principal lógica de negócios:
Primeiro execute os dados de inserção, se a inserção for bem-sucedida, então envie. Se um conflito de chave exclusiva for relatado ao inserir, a atualização será executada. Se três ações simultâneas de inicialização de dados ocorrerem ao mesmo tempo, as inserções de sess1 com sucesso, as inserções de sess2 e sess3 encontram um conflito de chave única e a inserção falha, ambas executarão a atualização, então o deadlock ocorre.
2.2 Preparação Ambiental
O nível de isolamento de transação do MySQL 5.6.24 é RR
create table ty (
id int not null primary key auto_increment ,
c1 int not null default 0,
c2 int not null default 0,
c3 int not null default 0,
unique key uc1(c1),
unique key uc2(c2)
) engine=innodb ;
insert into ty(c1,c2,c3) values(1,3,4),(6,6,10),(9,9,14);
2.3 Caso de teste
Para facilitar a análise do log de deadlock, os valores de c3 inseridos nas três sessões são 1 2 3 respectivamente, que na verdade são o mesmo valor em produção.
sess1 |
sess2 |
sess3 |
|
início; |
início; |
início; |
|
T1 |
inserir em ty (c1, c2, c3) os valores (4,4,1); |
||
T2 |
inserir em ty (c1, c2, c3) os valores (4,4,2); |
||
T3 |
inserir em ty (c1, c2, c3) valores (4,4,3); |
||
T4 |
comprometer |
||
T5 |
atualizar ty set c3 = 5 onde c1 = 4; |
||
T6 |
atualizar ty set c3 = 5 onde c1 = 4; ERROR 1213 (40001): Deadlock encontrado ao tentar obter o bloqueio; tente reiniciar a transação |
2.4 Registro de deadlock
2018-03-28 10:04:52 0x7f75bf2d9700
*** (1) TRANSACTION:
TRANSACTION 1870, ACTIVE 76 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 399265, OS thread handle 12, query id 9 root updating
update ty set c3=5 where c1=4
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 28 page no 4 n bits 72 index uc1 of table
`test`.`ty` trx id 1870 lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 1871, ACTIVE 32 sec starting index read,
thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 399937, OS thread handle 16, query id 3 root updating
update ty set c3=5 where c1=4
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 28 page no 4 n bits 72 index uc1 of table
`test`.`ty` trx id 1871 lock mode S
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 28 page no 4 n bits 72 index uc1 of table
`test`.`ty` trx id 1871 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (2)
Na verdade, basta olhar o log para ver que as atualizações das duas transações competem entre si, na ausência de cenários de lógica de negócios, porque não há operação de inserção, é difícil ter uma ideia eficaz para analisar o impasse.
2.5 Analise o log de deadlock
T1 s1 executa a operação de inserção, verifica a exclusividade e insere com êxito e mantém o bloqueio de linha da linha de registro c1 = 4.
A inserção T2 s2 encontra um conflito de chave exclusivo, solicite o bloqueio de bloqueio S O registro de bloqueio da próxima chave mostra o índice uc1 da tabela test.ty trx id 1870 modo de bloqueio S esperando
T3 é o mesmo que s2, a inserção s3 encontra um conflito de chave exclusivo, aplique o bloqueio de bloqueio S O registro de bloqueio da próxima chave mostra o índice uc1 da tabela test.ty trx id 1870 modo de bloqueio S esperando
T4 sess1 executa a operação de confirmação, neste momento sess2 e sess3 adquirem Lock S Next-key Lock ao mesmo tempo.
O aplicativo T5 recebe um conflito de chave exclusivo. A operação de atualização de sess2 precisa ser aplicada para um bloqueio de linha de c = 4, que é incompatível com o bloqueio de próxima chave Lock S mantido por sess3. Aguarde até que sess3 libere o bloqueio de chave próxima S de bloqueio.
T6 é semelhante ao sess2. A operação de atualização do sess3 precisa ser aplicada para um bloqueio de linha de c = 4, que é incompatível com o bloqueio da próxima chave Lock S mantido pelo sess2. Esperando que o sess2 libere o bloqueio da próxima chave Lock S. Uma espera cíclica ocorre e um deadlock ocorre.
2.6 Solução
A solução neste caso e de fato um impasse anterior em sete casos iguais, usando inserir na chave duplicada. O caso 7 é muito semelhante à lógica de negócios que causou o impasse neste artigo. Porque foi escrito pelo mesmo grupo de desenvolvedores.
Três resumos
A causa raiz do impasse é que a ordem de aplicação de bloqueios para transações diferentes é diferente e há espera cíclica. Ao projetar cenários de negócios de alta simultaneidade , os desenvolvedores precisam se concentrar neste ponto e tentar evitar impasses causados por cenários de negócios não razoáveis.
Além disso, o mecanismo de travamento da inserção é na verdade mais complicado do que a atualização, o que requer mais prática para esclarecer o processo de travamento.
Digitalize o código QR para seguir a conta pública do autor no WeChat
Leitura estendida
O texto completo acabou.
Aproveite o MySQL :)
A aula "MySQL Core Optimization" do professor Ye foi atualizada para o MySQL 8.0, leia o código para iniciar a jornada de prática do MySQL 8.0