Esse artigo sera
dividido em duas partes a primeira relatando o problema e possíveis soluções e
na segunda parte apresentaremos como remover transações distribuídas usando
COMMIT e ROLLBACK force.
Como resultado de uma falha
na confirmação de uma transação distribuída, algumas entradas podem ser gravadas
na visão DBA_2PC_PENDING e na DBA_2PC_NEIGHBORS. O evento acontece quando o processo
de recover (RECO) verifica essas visões para recuperar a transação que falhou.
No entanto, em alguns casos não é possível executar a recuperação. Isso ocorre
porque todos os locais que estavam envolvidos na transação não estão mais acessíveis.
Outra causa é a visão DBA_2PC_PENDING ficar com transações inconsistentes, que
é o tema deste artigo. Essa causa pode ainda ser classificada da seguinte
maneira:
1. Entradas na visão DBA_2PC_PENDING
para uma transação distribuída inexistente;
2.
Há uma transação distribuída para os quais não existem entradas no dba_2pc
exibições (inverso do item 1);
3. Como “limpar” (purgar) as transações distribuídas que estão com o “status” como
PREPARED. Esse erro ocorre quando uma transação distribuída trava. As visões DBA_2PC_PENDING
e DBA_2PC_NEIGHBORS armazenam os detalhes das transações que não foram
adequadamente resolvidas.
SOLUÇÕES
Para as
entradas na visão DBA_2PC_PENDING sem uma transação correspondente.
Neste caso a
visão DBA_2PC_PENDING apresenta as transações distribuídas, mas não há nenhum transação
pendente na realidade. Se o “status” da transação for confirmado, a transação
pode ser confirmada realizando um “COMMIT FORCE” ou pode-se voltar a transação
executando um “ROLLBACK FORCE”. Pode-se utilizar a package “DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY”,
para fazer o trabalho.
No entanto, se
o “status” da transação está em PREPARED e não há nenhuma entrada na tabela de
transação, então esta entrada pode ser limpa manualmente utilizando os passos
abaixo:.
SQL> set transaction use
rollback segment SYSTEM;
SQL> delete from
sys.pending_sessions$ where local_tran_id = [valor_local_tran_id];
SQL> delete from
sys.pending_sub_sessions$ where local_tran_id = [valor_local_tran_id];
SQL> commit;
Exemplo: A consulta a seguir relata uma transação
distribuída com o “status” PREPARED.
SQL> select
local_tran_id, state from dba_2pc_pending;
LOCAL_TRAN_ID STATE
----------------------
----------------
1.92.66874 prepared
Dado que a LOCAL_TRAN_ID é
composta por, '1.92.66874' está localizada no segmento de rollback #1 (SYSTEM).
Para encontrar a transação que está em execução deve-se utilizar a consulta
abaixo:
SQL> SELECT KTUXEUSN,
KTUXESLT, KTUXESQN, /* Transaction ID */,
KTUXESTA Status, KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!='INACTIVE'
AND ktuxeusn= 1; <== este é o número
do segmento de rollback em uso.
no rows selected
Para forçar o “ROLLBACK”,
usar:
SQL> rollback force
'1.92.66874';
ORA-02058: no prepared
transaction found with ID 1.92.66874
Neste caso, não é possível executar o “ROLLBACK FORCE”,
então deve-se realizar a limpeza desta transação manualmente:
SQL> set transaction use rollback segment SYSTEM;
SQL> delete from sys.pending_trans$ where local_tran_id = '1.92.66874';
SQL> delete from sys.pending_sessions$ where local_tran_id = '1.92.66874';
SQL> delete from sys.pending_sub_sessions$ where local_tran_id = '1.92.66874';
SQL> commit;
SQL> delete from sys.pending_trans$ where local_tran_id = '1.92.66874';
SQL> delete from sys.pending_sessions$ where local_tran_id = '1.92.66874';
SQL> delete from sys.pending_sub_sessions$ where local_tran_id = '1.92.66874';
SQL> commit;
Em nosso próximo artigo apresentarei a continuação deste assunto…
Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com