[firebase-br] Travar registro no BD

Escovador de Bits escovadordebits em gmail.com
Sáb Jun 6 12:26:21 -03 2009


Bom dia/tarde Marcelo.

Grande Marcelo, aqui vai a minha humilde sugestão:

Cada instância da aplicação é um processo separado, independente de está 
sendo executado em máquinas diferentes ou na mesma máquina.

O próprio sistema operacional gera um número de identificação de 
processo (PID), como se fosse um CPF do processo, e dependendo da 
linguagem de programação a ser utilizada, você tem como obter o número 
do seu processo. E em último caso, a aplicação pode simplesmente gerar 
um número aleatório.

Utilizando o número do próprio processo, ou um valor aleatório, 
raramente o valor gerado por um processo coincidirá com o valor gerado 
por outro processo.

Seguindo essa lógica, poderia executar os seguintes passos:

1 - Acrescente um campo de "identificação de processo", ou seja, algo como:

ALTER TABLE CAMPANHA_LANCAMENTO ADD IDENTIFICADOR INTEGER;

2 - Crie um índice para agilizar as pesquisas pelo novo campo:

CREATE INDEX IX_CAMP_LANC_IDENT ON CAMPANHA_LANCAMENTO (IDENTIFICADOR);

Acredito que você já tenha criado um índice para o campo ENVIADO.

3 - Inicie uma nova transação (com ReadCommited e Wait).

4 - Para reservar um dos registros, execute um comando SQL como o seguinte:

UPDATE CAMPANHA_LANCAMENTO CL SET
  CL.IDENTIFICADOR = <número-do-processo>
WHERE
  (EXISTS(SELECT C.ID_CAMPANHA FROM CAMPANHA C WHERE C.ID_CAMPANHA = 
CL.ID_CAMPANHA))AND
  (CL.ENVIADO = 'N')AND
  (CL.IDENTIFICADOR IS NULL);

5 - Efetive (commit) a transação atual que é muito curta.

6 - Verifique se conseguiu reservar algum registro:

SELECT
  *
FROM
  CAMPANHA_LANCAMENTO
WHERE
  IDENTIFICADOR = <número-do-processo>;

Normalmente, quando você configura uma transação para esperar por algum 
tempo (wait), caso haja algum conflito de travas, o Firebird espera por 
cerca de 10 segundos (padrão) até que o conflito seja resolvido.

Caso o conflito não seja resolvido nesse tempo (que é configurado na 
própria transação quando ela é iniciada), apenas uma das transações 
conflitantes é eleita para prosseguir, e as demais recebem o respectivo 
erro de conflito.

Como os passos 3, 4 e 5 ocorrem muito rapidamente, dificilmente atingirá 
o tempo limite de espera, e nesse caso, acredito que mesmo que vários 
processos tentem alterar o mesmo registro, nenhum deles receberá a 
mensagem de erro de conflito, e o último valor salvo no campo 
IDENTIFICADOR permanecerá.

No passo 6, cada processo já terá reservado, ou não, algum registro, e 
nesse passo não haverá conflito, pois cada processo acessará o registro 
que terá o seu próprio identificador.

Dessa forma, após efetuar o processamento daquele registro, o processo 
pode executar, sem problemas, o seguinte comando SQL:

UPDATE CAMPANHA_LANCAMENTO SET
  IDENTIFICADOR = NULL,
  ENVIADO = 'S'
WHERE
  IDENTIFICADOR = <número-do-processo>;

De qualquer forama, é apenas uma sugestão de solução.

Espero ter ajudado mais que atrapalhado. :D

Marcelo Moreira escreveu:
> Pessoal,
> Boa tarde!
>
> Preciso que um determinado registro na tabela seja travado de modo que outro
> usuario nao tenha acesso ha ele. Vou tentar explicar a situação:
> O sistema vai fazer o envio de email e os cliente para quem ele deve mandar
> o emai vai ficar nesta tal tabela. o que acontece é que vao ser mais de um
> sistema aberto fazendo o envio destes email e o sql que estou usando para
> pegar sempre o ultimo registro que ainda nao foi enviado o email seria este:
>
>
> select
>     first( 1 )
>     CL.NUMERO,
>     C.MENSAGEM
>
> from
>     CAMPANHA_LANCAMENTO CL
>
> inner join CAMPANHA C on (CL.ID_CAMPANHA = C.ID_CAMPANHA)
>
> where
>     CL.ENVIADO = 'N'
>
> ou seja nenhum outro sistema quando fizer o mesmo select nao pode ter acesso
> a este registro. e depois que o sistema fizer o envio do email eu altero o
> campo: CL.ENVIADO = 'S'
>
> Como eu poderia resolver isto.
>
> Obrigado pela atencao.
>
> Abraços
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.locador.com.br
> Para saber como gerenciar/excluir seu cadastro na lista, use: http://www.firebase.com.br/fb/artigo.php?id=1107
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
>
>   




Mais detalhes sobre a lista de discussão lista