BLOQUEAR NOVAS LEITURAS EM BD FIREBIRD

ARCADYUM 15/05/2017 21:53:36
#473971
Prezados,
Estou com uma situação e gostaria da ajuda de vocês. Tenho um sistema que realiza o controle de fluxo de documentos do lugar onde trabalho. Cada setor que necessita enviar um documento para fora deve ser cadastrado no sistema de forma que o setor de protocolo possa dar ciência ao usuário de que recebeu o documento. Cada documento cadastrado recebe um número sequencial que identifica o documento. Até duas semanas esse controle do número sequencial funcionou muito bem da forma como havia desenvolvido, porém, aconteceu de dois documentos sairem com numeração igual. Acredito que na hora da leitura do último registro tenha ocorrido, simultaneamente, com duas instâncias do programa e houve a duplicidade da informação. Portanto, há como bloquear a leitura da linha?

O que preciso é:

Quando uma instância do programa realizar a leitura da linha, ela seja bloqueada, nenhuma outra instância realiza a leitura (fica em modo de espera);
O programa vai realizar o cálculo para incrementação da sequência;
Vai realizar o update modificando o último valor e após desbloquear para nova leitura e incrementação e assim sucessivamente.

Utilizo Firebird 2.5.




DS2T 15/05/2017 22:05:32
#473974
Você está passando por problemas de concorrência.
Estás a usar o SELECT MAX() + 1 AS ProximoCodigo From Tabela... pra poder gerar o próximo campo de incremento? Se for, provavelmente aí tá o problema... Isso funciona apenas para banco de dados monousuário (multiusuário, dependendo da frequência de inserts até vai também, mas aí você vai estar contando com a sorte).

Pelo que eu saiba, Firebird não possui um tipo de dados de autoincremento... mas provavelmente deve ter alguma saída mais elegante, até porque é um banco projeto para multiusuário... Não tive tanto contato assim com Firebird...
Se ninguém responder até amanhã, eu dou uma pesquisada.

Abraços!
ARCADYUM 15/05/2017 22:28:50
#473978
Eu realizo o select, pego o valor, realizo as operações de incremento e dou o update. Como disse anteriormente, em algum momento duas instâncias do programa realizaram a mesma leitura e realizaram as mesmas operações gerando a duplicidade. Auto incremento no campo seria complicado pois o número de controle ocorre da seguinte forma xx/xxxx sendo xx o número e xxxx o ano. Por isso, o programa realiza os procedimentos de separação, incrementação e update na tabela. Neste momento preciso que a leitura seja bloqueada até que a instância que esteja realizando as operações a libere para nova operação. Já realizei uma série de pesquisas e nenhuma me retornou um resultado satisfatório.
GUIMORAES 16/05/2017 08:57:35
#473984
ARCADYUM

Acredito que esta não seja a melhor forma de se trabalhar com um campo que te servirá como chave primária. O ideal seria você criar um campo auto-incremento (utilizando generator e uma trigger), e em seguida [Ô]pegar[Ô] este valor para realizar os updates (você pode fazer um select no generator para isto).
Existe outra forma de se fazer isto. Antes de fazer o insert, você pode gerar uma GUID para gerar uma chave única (mas não deve ser a chave primaria), e utilizar ela como parâmetro para o seu select max(), será muito difícil que ocorra uma numeração com duplicidade após fazer desta forma, mas mesmo assim é importante utilizar o generator + trigger para esta operação, deixando que o banco de dados faça a geração do campo auto-numérico.

LLAIA 16/05/2017 09:46:49
#473985
Basta usar generator com trigger. A versão mais atual do Firebird tem autoincrement agora. Não sei se o generator da versão 2.5 tem um nextvalue como as sequences no Oracle.
ARCADYUM 16/05/2017 09:58:22
#473986
Pessoal,
Acho que me expressei mal. Essa linha que eu preciso travar não possui chave primária, é só uma tabela com um único campo, que servirá como controle de numeração dos documentos que são enviados.
Como disse eu faço um select na tabela, como ela possui somente uma linha e um campo, eu pego o valor desse campo. Como o formato desse valor é XX/XXXX eu faço o tratamento dessa informação no programa. Eu separo o número da data, incremento e faço o update. é neste momento em que o programa está tratando esses dados que a tabela deve ser bloqueada para leitura. Após o Update ele destrava a tabela permitindo novas operações.
LLAIA 16/05/2017 10:20:51
#473987
Já que essa tabela só tem um campo, vou ser um pouquinho chato e insistir contigo com o Generator!

é preciso usar uma tabela com um registro, no caso, vc pode usar a tabela de sistema do FB. No Oracle usamos [ô]Dual[ô]

Experimenta isso num recordset:
SELECT GEN_ID(Nome_Generator_NUmeracao_Docs, 1) FROM RDB$DATABASE


Ao criar o generator no banco, vc precisa atribuir pra ele o último número dessa tabela. Deixe o banco trabalhar trabalhar pra vc.
GUIMORAES 16/05/2017 11:06:48
#473989
Citação:

:
Pessoal,
Acho que me expressei mal. Essa linha que eu preciso travar não possui chave primária, é só uma tabela com um único campo, que servirá como controle de numeração dos documentos que são enviados.
Como disse eu faço um select na tabela, como ela possui somente uma linha e um campo, eu pego o valor desse campo. Como o formato desse valor é XX/XXXX eu faço o tratamento dessa informação no programa. Eu separo o número da data, incremento e faço o update. é neste momento em que o programa está tratando esses dados que a tabela deve ser bloqueada para leitura. Após o Update ele destrava a tabela permitindo novas operações.





ARCADYUM
Independente se você usa uma tabela para gerenciar uma chave única (como se fosse uma chave primária), o insert deverá ter uma chave primária também, para identificar que este registro será único no seu banco de dados, certo?
Você pode utilizar este número que você está gerando como um campo de referência, mas em conjunto com uma chave primária.
A falta disto é uma péssima prática, e acredito que você já esteja sofrendo as consequência de não planejar a sua estrutura de dados, o que torna o seu banco de dados muito redundante, passível de erros. Não quero ser o chato, mas acredito que você deve repensar na estrutura de dados que definiu.


Citação:

:
Já que essa tabela só tem um campo, vou ser um pouquinho chato e insistir contigo com o Generator!

é preciso usar uma tabela com um registro, no caso, vc pode usar a tabela de sistema do FB. No Oracle usamos [ô]Dual[ô]

Experimenta isso num recordset:

SELECT GEN_ID(Nome_Generator_NUmeracao_Docs, 1) FROM RDB$DATABASE


Ao criar o generator no banco, vc precisa atribuir pra ele o último número dessa tabela. Deixe o banco trabalhar trabalhar pra vc.



Também sou a favor de criar um generator para esta finalidade, é possível fazer isto que você faz com o generator, basta pensar um pouquinho.

Um abraço.
Tópico encerrado , respostas não são mais permitidas