28/09/2004

Concorrencia em Transações

Pessoal, gostaria de saber, como faço para que, quando o usuário clicar em Editar (IBTable.Edit), se outro usuario já estiver usando o registro, aparecer uma mensagem dizendo que o registro está em uso e não deixar ele alterá-lo. Já vi muita coisa a respeito, e até consegui fazer usando DBExpress, ADO, BDE. Porém, com a palheta IBX ainda não consegui, e ficaria muito grato a quem puder me ajudar. Queria fazer isso através de transações e Níveis de Isolamento.

Uso Delphi 7 Enterprise
FireBird 1.5
Componentes IBX - (palheta Interbase)
Windows XP Pro


Thomaz_prg

Respostas

28/09/2004

Vinicius2k

Colega,

Se vc conseguiu com dbExpress, a forma é a mesma, mas NÃO com IBTable...

Use uma IBQuery ou IBDataSet com a instrução SQL +/- assim :
select {lista de campos} from TABELA where CAMPO_CHAVE = VALOR for update with lock

Enquanto o usuário que fizer o primeiro select não commitar a transação dele, o segundo usuário não irá conseguir efetuar updates neste registro.

Configure o IBTransaction com a opção no NOWAIT se quiser q a exceção seja retornada imediatamente.

Bem, vc deve saber q isso se chama travamento pessimista e o nome já diz tudo... é pessimista e na maioria dos casos desnecessário... mas isso depende do contexto da sua aplicação e não posso julgar se no seu caso é necessário ou não...

Sugiro que leia este artigo : http://www.comunidade-firebird.org/cflp/downloads/CFLP_T032.PDF

T+


Responder Citar

29/09/2004

Thomaz_prg

valeu mesmo pela dica anterior. Porém, se eu fosse utilizar um dbnavigator, e dbedit´s como ficaria, porque daí eu não poderia usar uma clausula select para bloqueio.

E, usando uma IBquery, como ficaria. Agradeço sua ajuda, e peço compreensão, pois, estou tendo que dar manutenção num sistema que não é meu, e como não tenho o hábito de trabalhar com IBX, tenho que perguntar.

Agradeço antecipadamente quem puder me ajudar...


Responder Citar

29/09/2004

Vinicius2k

valeu mesmo pela dica anterior. Porém, se eu fosse utilizar um dbnavigator, e dbedit´s como ficaria, porque daí eu não poderia usar uma clausula select para bloqueio..

Se vc quer dizer num IBTable, realmente não tem jeito. Infelizmente não existe outra forma. É assim que se faz travamento no IB/FB,

E, usando uma IBquery, como ficaria.

No caso seria melhor utilizar um IBDataSet com a instrução de forma que só retorne um registro... a sua edição, ao invés de ser efetuada na IBTable, seria no IBDataSet e controlando a transação.

Para tentar diminuir sua dificuldade inicial com o IBX, veja este tópico, do colega afarias: http://delphiforum.icft.com.br/forum/viewtopic.php?t=30575


T+


Responder Citar

30/09/2004

Thomaz_prg

Cara, obrigado pela sua atenção e pela sua ajuda.
Vou testar agora e, verei se funciona como quero.


Responder Citar

30/09/2004

Thomaz_prg

E aí pessoal, beleza?
Bom, fiz exatamente como estava no exemplo do A.Farias, porém, quando abro o sistema 2 vezes, começo a editar um regostro, e no outro, abro para edição o mesmo registro e salvo dá erro.
Acrescentei o que o Vinicius falou. Select * from Clientes where codigo = :cod For Update With Lock, porém ao selecionar um clientes (como no exemplo do A.Farias), ele dá erro. Se tiro a parte do ´for update with lock´ ele funciona. Só que permite que um mesmo registro seja alterado por mais de 1 usuário ao mesmo tempo.

Fico grato a quem puder me ajudar, e grato a quem já ajudou...

Mais uma vez obrigada,


Responder Citar

01/10/2004

Thomaz_prg

Pessoal, o que quero saber é, simplesmente, como bloquear o acesso a para edição (edit) de um registro, se o mesmo já estiver sendo editado por outro usuário (travamento pessimista) com os componentes IBX. Tentei select * from Cliente where codigo = :cod For Update With Lock´, porém dá um erro, dizendo que não é possível manipular um cursor já aberto.

Ficaria muito agradecido a quem me ajudar.


Responder Citar

01/10/2004

Afarias

|Pessoal, o que quero saber é, simplesmente, como bloquear o acesso a
|para edição (edit) de um registro, se o mesmo já estiver sendo editado
|por outro usuário (travamento pessimista) com os componentes IBX.

Usando IB/FB simplesmente, faça::

Edit;
{
Simule a alteração em algum campo tipo::
FieldByName(´CODIGO´).AsInteger := FieldByName(´CODIGO´).AsInteger;
}
Post;

Pronto! O registro estará travado PARA ALTERAÇÃO até q seja dado um COMMIT ou ROLLBACK (ou seus respectivos ´retainings´)


|quando abro o sistema 2 vezes, começo a editar um regostro, e no
|outro, abro para edição o mesmo registro e salvo dá erro

Exatamente o q vai ocorrer. O erro indica q o registro está ´travado´ e não pode ser alterado -- vc deve tratar essa exceção informando isso ao usuário. Se não quiser isso, vc pode colocar sua transação em WAIT -- mas ai, esteja certo q suas transações sejam curtas ou o usuário vai ficar ´travado´


T+


Responder Citar

01/10/2004

Thomaz_prg

Fico muito grato pela sua atenção.
Porém que queria que a exceção fosse dada quando eu clicasse no botão com o comando IBDataSet.Edit e não no Post como está acontecendo.
O Vinicius me passou uma dica que até funcionou. O comando

select [campos] from [tabela] for update with lock

só que só funciona se eu tirar o ´FOR UPDATE´. Ou seja, pelo simples fato de selecionar o registro, mesmo que seja para consulta, ele fica bloqueado. Li alguns artigos que dizem que este recurso (FOR UPDATE) está incluso no FB 1.5 (Versão que uso), porém ele não aceita.

Desculpe a insistencia, mas é que tentei (e ainda estou tentando), e estou procurando material na internet, porém não achei nada.

Ficaria muito grato se alguém pudesse me ajudar nesta dúvida. Novamente, obrigado.


Responder Citar

01/10/2004

Afarias

|Porém que queria que a exceção fosse dada quando eu clicasse no
|botão com o comando IBDataSet.Edit e não no Post como está
|acontecendo.

:D hehehe... mas olhe com atenção...

se quando for editar, vc vai usar o código::

Edit; 
FieldByName(´CODIGO´).AsInteger := FieldByName(´CODIGO´).AsInteger; 
Post; 
Edit;


Que é para travar o registro. Então, vc terá a exceção exatamente assim q o usuário clicar em EDITAR, não é mesmo?? :wink:


T+


Responder Citar

01/10/2004

Thomaz_prg

Desculpe-me, creio não ter sido claro.
O caso que estou dizendo é o seguinte:

Na máquina A eu seleciono o Registro 1 e clico em editar (IBDataSet.Edit).
Na máquina B outro usuário seleciona o Registro 1 e clica em editar (IBDataSet.Edit).

No caso, eu queria que quando o comando de edição fosse colocado na máquina B, o usuário recebece uma mensagem do tipo ´Registro sendo alterado em outro terminal´. Mas isto é que não está aocntecendo.

Desculpe mais uma vez a minha insistencia, mas é que realmente estou precisando fazer isso.

Mas uma vez, obrigado.


Responder Citar

02/10/2004

Thomaz_prg

E aí galera, será que alguém pode me ajudar?


Responder Citar

04/10/2004

Afarias

Amigo, não sei se sou eu q não estou sendo claro!

A solução está ai na sua cara e vc à está despresando. Quando o usuário clicar em algum botão para EDITAR apenas chame o código postado acima.



T+


Responder Citar