
Anderson Graf
Row Locks (TX) - Como identificar a linha bloqueada
Atualizado: 18 de ago. de 2021
Em um banco de dados multiusuários como o Oracle database, é necessário que exista algum tipo de bloqueio de dados para que possam ser resolvidos os problemas associados à simultaneidade, consistência e integridade de dados. Estes bloqueios são mecanismos que impedem a interação destrutiva entre as transações que acessam o mesmo recurso.
Um dos tipos de bloqueios existentes é o bloqueio (lock) de linha identificado pelo evento de espera (wait event) "enq: TX - row lock contention".
Um lock do tipo linha ocorre naturalmente sobre a linha de uma tabela, ou seja, enquanto uma linha (registro) está "alocado", nenhuma outra sessão conseguirá alterá-lo até que a transação que originou o lock chegue ao seu fim, seja por commit ou rollback.
A identificação de um lock transacional (TX) pode ser realizada de diferentes formas, aqui utilizaremos o script utllockt.sql distribuído pela própria Oracle e encontrado abaixo do $ORACLE_HOME/rdbms/admin
Montando o cenário:
SESSÃO 1:
Observe que ao final do UPDATE não foi executado commit ou rollback;
SESSÃO 2:
A sessão 2 (sid=51) ao tentar realizar a alteração da mesma linha da sessão 1 (sid=58) ficou "travada" pois a linha id=1 está bloqueada até que a sessão 1 realize um commit ou rollback do registro.
SESSÃO 3:
A sessão 3 (sid=56) ao tentar alterar a mesma linha que a sessão 2 (sid=51) também ficou presa, pois a sessão 2 ainda não concluiu sua transação, desta forma existe a sessão 2 aguardando a sessão 1 e a sessão 3 aguardando a sessão 2 conforme árvore de bloqueio abaixo:
SESSÃO 4:
Cenário de bloqueio:

Identificando as linhas bloqueadas:
Sempre que uma sessão fica aguardando um lock transacional (row lock – TX), algumas informações adicionais são populadas na v$session:

Utilizando-se destes dados é possível identificar o ROWID da linha bloqueada.
O ROWID é uma pseudocolumn que representa o endereço de cada linha de uma tabela. Os valores desta pseudocoluna são strings que podem conter os caracteres A-Z, a-z, 0-9 e o sinal de mais (+) e a barra (/).
Os rowids são formados pelas seguintes informações:
Data block: Bloco de dados que contém a linha;
Row: Linha no bloco de dados;
Database file: Arquivo de dados que a linha;
Data object number: Número de identificação do objeto.
Agora basta utilizar o pacote DBMS_ROWID para interpretar os conteúdos de rowid. As funções do pacote extraem e fornecem informações sobre os quatro elementos rowid listados acima.
Como as colunas ROW_WAIT_* da v$session são populadas apenas quando uma sessão está aguardando alguma transação, podemos identificar a rowid (endereço da linha) que as sessões 2 (sid=51) e 3 (sid=56) estão aguardando.
Linha bloqueada da sessão 2:
Linha bloqueada da sessão 3:
Neste exemplo (cenário), como não foi utilizado bind variables nas operações DML é possível identificar também o valor bloqueado pelo próprio texto sql da instrução:
Com a utilização de bind variables a instrução retornada seria similar a:
update teste set id=:b2 where id=:b1
A identificação da instrução também é importante para saber quais colunas estão sofrendo alterações, pois a linha retornada pelo rowid pode conter várias colunas diferentemente do exemplo onde a tabela possuía apenas uma coluna.
Referências:
https://docs.oracle.com/database/122/CNCPT/data-concurrency-and-consistency.htm#CNCPT1313
https://docs.oracle.com/database/122/REFRN/V-SESSION.htm#REFRN30223
https://docs.oracle.com/database/122/SQLRF/Data-Types.htm#SQLRF50998