Escolar Documentos
Profissional Documentos
Cultura Documentos
1 – Bloqueios (Locks)
Numa base de dados como o MySQL os dados são consultados e alterados concorrentemente
pelos vários utilizadores. O que acontece se dois utilizadores tentarem alterar o mesmo dado
ao mesmo tempo? O primeiro a chegar ativa um bloqueio (LOCK) que só é retirado quando a
sua transação terminar. A segunda transação terá que esperar que o bloqueio seja retirado, o
que só acontece quando a primeira transação termina.
collate=latin1_bi
n ;
4 starttransaction;
comeca uma transacao
5 insertinto teste (id,nome)
inserir nos atributos id e nome os valores
values
(1,'José')
,(2,'João')
,(3,'joão')
,(4,'joaquim')
,(5,'josé')
,(6,'Joaquim');
rever todos atrivutos inseridos
select * from teste;
6 commit;
confirmar a transcao
7 starttransaction;
comeca uma transacao
8 update teste set
atualizar na tabela teste para nome “11111”
nome=’111111’ where
onde o id = 5
id=5;
Essa linha recebe um bloqueio (LOCK).
9 starttransactio
n; comeca uma transacao no utilizador 2
A sequência de comandos abaixo cria duas transações que se vão bloquear mutuamente,
provocando um “DEAD-LOCK”:
Um DEAD-LOCK é uma situação em que a segunda transação está à espera de um recurso que
está bloqueado pela primeira, enquanto a primeira espera por um recurso que está bloqueado
pela segunda. Teríamos uma espera infinita se não fosse o mecanismo existente na base de
dados que deteta automaticamente as situações de DEAD LOCK, provocando o ROLLBACK
automático da segunda transação.
Se na sequência de comandos anterior o utilizador demorar muito tempo a introduzir os
comandos 11 e 12 poderá não obter um DEAD LOCK. Isto porque, se for excedido o tempo de
espera pela libertação de um bloqueio os comandos são abortados, como foi visto no ponto
anterior.
Para evitar situações de DEAD LOCK recomenda-se o seguinte:
As transações devem ser tão curtas quanto possível;
Todas as transações devem alterar os dados na mesma ordem. Por exemplo
primeiro o id=1 e depois o id=5;
1.3 – Lock in share mode e a integridade referencial
Vamos criar um cenário em que uma tabela PARENT tem um relacionamento com uma tabela
CHILD, possuindo a base de dados uma restrição de integridade referencial. O utilizador 2 vai
executar uma transação onde começa por verificar que existe a linha com ID=2 em PARENT e
vai tentar inserir em CHILD uma linha que se relaciona com esse PARENT. Depois da verificação
e antes do INSERT o utilizador 1 vai eliminar a linha de PARENT e por isso o INSERT do
utilizador 2 vai falhar.
TEMPO UTILIZADOR 1 UTILIZADOR 2 COMENTÁRIOS
1 starttransaction; Iniciar uma nova transação.
2 drop table if exists
child;
drop table if exists
parent;
TEMPO UTILIZADOR 1 UTILIZADOR 2 COMENTÁRIOS
create table parent Criar tabela PARENT e CHILD e
( inserir registos.
id integer,
Os comandos DDL fazem COMMIT
nome varchar(50),
implícito, mas não terminam a
primary key (id)
transação.
);
create table child
(
id integer,
nome varchar(50),
id_parent integer,
primary key (id),
foreign key
(id_parent)
references
parent(id)
);
insert into parent
(id,nome) values
(1,'aaaa')
,(2,'bbbb');
insert into child
(id,nome,id_parent)
values
(1,'child aaaa',1)
,(2,'child
bbbb',1);
3 commit;
confirmar a transcao
4 starttransaction;
comeca uma transacao no utilizador
2
5 select * from Validar na tabela PARENT existe uma
parent where id=2 linha com ID 2, já que vamos tentar
inserir dados em CHILD associados a
este PARENT.
6 start transaction;
comeca uma transacao no utilizador
delete from parent where 2
id=2;
Para resolver este problema o SELECT do utilizador 2 deveria ter sido feito com um bloqueio:
select * fromparentwhere id=2 lock in share mode – é atribuído um bloqueio do tipo
SHARED LOCK;
select * fromparentwhere id=2 for update – é atribuído um bloqueio do tipo
EXCLUSIVE LOCK;
Depois de atribuído um dos dois bloqueios acima, o utilizador 1 não consegue fazer o DELETE
(nem qualquer outra alteração) enquanto a transação do utilizador 2 estiver a decorrer.