Primeiramente, bloquear uma tabela não impedirá que outra sessão emita
SELECT
declarações contra os dados. Na Sessão 1, se eu bloquear a tabela
SQL> lock table foo in exclusive mode;
Table(s) Locked.
Eu posso então iniciar a Sessão 2 e consultar todos os dados que eu gostaria
SQL> select * from foo;
COL1
----------
1
1
No Oracle, os gravadores não bloqueiam os leitores, portanto, você nunca pode impedir que outra sessão consulte os dados em uma tabela.
Parece que o que você está tentando implementar é um bloqueio pessimista. Nesse caso, em vez de bloquear a tabela, você faz um
SELECT FOR UPDATE
que bloqueia a entrada específica que você pretende processar. Contanto que todas as outras sessões também tentem fazer um SELECT FOR UPDATE
(dependendo da versão do Oracle, potencialmente adicionando o SKIP LOCKED
qualificador e/ou o WAIT
qualificador). Isso bloqueia a linha específica que você está processando e permite que a segunda sessão selecione uma linha diferente ou limite o tempo limite ou descubra que não há linhas para processar, dependendo das especificidades da implementação. Isso não envolve bloquear a tabela. A única maneira de um bloqueio ser liberado é que a sessão que o adquiriu o libere (geralmente encerrando a transação) ou que a sessão que o adquiriu seja encerrada. Se o aplicativo cliente ainda estiver em execução, mas não estiver fazendo nada para liberar o bloqueio ou encerrar a sessão, o bloqueio será mantido indefinidamente. Um DBA precisaria matar explicitamente a sessão, deixando a transação reverter e liberando o bloqueio para que o sistema se movesse novamente. Se o aplicativo cliente parar de ser executado ou, pelo menos, parar de responder (ainda não entendi exatamente qual cenário de falha você está discutindo), é possível que habilitar a detecção de conexão morta (DCD) por meio do parâmetro 'SQLNET.EXPIRE_TIME' no nível do banco de dados faria com que o banco de dados determinasse que o cliente não responde e encerrasse automaticamente a sessão, revertendo a transação e liberando o bloqueio.
No entanto, se houver várias sessões processando dados, geralmente é preferível usar alguma forma de bloqueio otimista. Caso contrário, você está projetando um sistema que inevitavelmente precisará que o DBA encontre e elimine sessões com urgência para que os usuários de negócios voltem a trabalhar e isso exigirá cada vez mais intervenção quanto mais ocupado estiver. Isso não é algo que os DBAs gostem de fazer e não é algo que os usuários de negócios gostem de reclamar. Um esquema de bloqueio otimista simples seria algo como
- Selecione uma chave para processar e algum tipo de data que indique a última vez que a linha foi atualizada.
- Atualize uma coluna de status para "processando" para que outras sessões não tentem processar a mesma linha.
- Processar a entrada em seu aplicativo
- Ao terminar o processamento, atualize os dados usando a chave e o horário que você selecionou na primeira etapa. Se você atualizar 1 linha, saberá que nenhuma outra sessão modificou os dados em questão desde que você os selecionou. Se você atualizar 0 linhas, saberá que alguma outra sessão modificou os dados desde que você os selecionou.
Com esse tipo de arquitetura, é relativamente fácil consultar o banco de dados para ver quais linhas estão sendo processadas e, por exemplo, ter um trabalho que defina a coluna de status de volta para "não processado" após algum período de tempo se o cliente não tiver finalizado. É realmente fácil para outras sessões escolher uma linha diferente para processar. E é relativamente seguro se, por exemplo, o aplicativo congelar por algumas horas e depois se recuperar, já que ele descobre que, depois de concluir o processamento, alguma outra sessão já reprocessou a linha.