Abrir SQLQuery está com erro de ´Cursor not returned´
27/08/2004
0
Atualmente estou desenvolvendo uma rotina utilizando D7 + Firebird 15 + dbExpress + Driver UIBFire15 (free) e neste desenvolvimento preciso fazer um travamento de registro (pessimista).
Estou fazendo da seguinte forma
qry.close;
qry.sql.clear;
qry.sql.add(´select pedido_venda from SEQUENCIA´);
qry.sql.add(´for update with lock´); // comando para travar registro
qry.open;
Logo apos realizar o open no SqlQuery o Delphi da o erro: ´Cursor not returned from Query´
1) Como posso resolver este problema ou como faço para fazer travamento de registro utilizando D7 + Firebird15 + DbExpress.
2) Gostaria de saber se assim como o Firebird tem o comando SQL para travamento de registro, outros bancos de dados tb tem? Como por exemplo SqlServer, Oracle e Sybase?
Andrevinni
Posts
27/08/2004
Vinicius2k
A instrução está correta : ... FOR UPDATE WITH LOCK ...
À primeira vista creio eu q está faltando o WHERE... desta forma vc não está informando ao servidor qual registro travar...
Espero ter ajudado...
T+
27/08/2004
Andrevinni
1) select pedido_venda from SEQUENCIA where empresa = 1 for update with lock
2) select pedido_venda from SEQUENCIA where empresa = 1 for update
3) select pedido_venda from SEQUENCIA for update with lock
e nenhuma delas funciona para travar o registro no firebird. Teria uma outra solucao pra este travamento pessimista? Desta forma via sentenca seria bom pq o proprio bco gerenciaria o travamento, se funcionasse iria ficar show de bola.
Olha Vinicius2k, jah pesquisei bastante sobre transacao aqui mesmo neste forum e vi muitas respostas suas sobre controle de transacao. Devido algumas resposta percebi q nao há necessidade de abrir transacao se estiver trabalhando com ClientDataSet e usando ApplyUpdates. Porem se eu abrir uma transacao, depois utilizar varios ApplyUpdates e antes do Commit acontecer um pique de energia os dados aplicados serao salvos ou nao?
27/08/2004
Vinicius2k
1. Consegui simular seu erro...
O problema está no driver, e é o primeiro problema que eu encontrei com ele... fiquei desanimado agora... :?
Troque para o driver nativo dbexpint.dll e seu problema será solucionado...
A instrução para travamento é :
select PEDIDO_VENDA from SEQUENCIA where EMPRESA = 1 for update with lock
2. Sobre as transações...
Realmente se vc não fizer o controle explícito da transação a MIDAS irá fazer... mas vc fizer o isolamento do(s) ApplyUpdates dentro de uma transação controlada por você ela só será ´commitada´ ao seu sinal, se não houver commit, quando da desconexão com o banco, o rollback é automático (Incluindo neste contexto uma possível queda de energia)...
Se não for dado commit, todos os ApplyUpdates envolvidos naquela transação são perdidos...
Um erro comum é pensar em proteger o ApplyUpdates em blocos Try/Except o que não faz sentido... pq um ApplyUpdates não gera exceção
[b:5331f6e9ff]ERRADO:[/b:5331f6e9ff]
TD.TransactionID := 1; TD.IsolationLevel := xilReadCommitted; SQLConnection1.StartTransaction(TD); try CDS.ApplyUpdates(0) SQLConnection1.Commit(TD); except SQLConnection1.Rollback(TD); end;
Neste exemplo *errado* o Rollback nunca será efetuado.
[b:5331f6e9ff]CORRETO:[/b:5331f6e9ff]
TD.TransactionID := 1; TD.IsolationLevel := xilReadCommitted; SQLConnection1.StartTransaction(TD); if CDS.ApplyUpdates(0) = 0 then begin SQLConnection1.Commit(TD); ShowMessage(´Aplicado com sucesso!´); end else begin SQLConnection1.Rollbabck(TD); ShowMessage(´Ocorreram erros !´); end;
Neste exemplo é dado o Commit se não houverem erros no ApplyUpdates.
Um exemplo mais ´complexo´:
var TudoOK: Boolean; try TudoOK:= False; TD.TransactionID:= 1; TD.IsolationLevel:= xilReadCommitted; SQLConnection1.StartTransaction(TD); {****} if ClientDataSet1.ApplyUpdates(0) > 0 then if ClientDataSet2.ApplyUpdates(0) > 0 then if ClientDataSet3.ApplyUpdates(0) > 0 then TudoOK:= True; {****} if TudoOK then SQLConnection1.Commit(TD) else begin ShowMessage(´Ocorreram erros !´); SQLConnection1.Rollback(TD); end; except On E: Exception do ShowMessage(´Não foi possível abrir a transação.´ + #13 + E.Message); end;
Aqui eu usei try/except mas não para controlar a transação e sim para exibir uma mensagem caso ocorra algum erro na abertura dela... o controle está sendo feito baseado no valor de retorno do ApplyUpdates, que deve ser sempre = 0 (zero), caso contrário não grava nada...
Para exibir o erro e/ou tratá-lo vc precisa trabalhar no evento OnReconcileError do ClientDataSet...
Lá vc pode, além de mostrar uma mensagem personalizada, tomar alguma providência em relação ao erro setando a variável ´Action´, por exemplo :
Action:= raCancel; Shomessage(´O erro ocorrido foi: ´ + E.Message);
Espero ter ajudado...
T+
27/08/2004
Vinicius2k
Erro de digitação...
Neste trecho :
{****} if ClientDataSet1.ApplyUpdates(0) > 0 then if ClientDataSet2.ApplyUpdates(0) > 0 then if ClientDataSet3.ApplyUpdates(0) > 0 then TudoOK:= True; {****}
Leia-se :
{****} if ClientDataSet1.ApplyUpdates(0) = 0 then if ClientDataSet2.ApplyUpdates(0) = 0 then if ClientDataSet3.ApplyUpdates(0) = 0 then TudoOK:= True; {****}
T+
28/08/2004
Andrevinni
Obrigado pelas respostas que esta me ajudando e muito. Agora consigo perceber a importancia em alguns momentos o travamento pessimista e o controle de transacao.
Eu jah suspeitava o que o problema era no driver, porem nao tive a ideia de utilizar a dxExpint.dll
Porem ainda estou com uma duvida?
1) Troquei a dll e funcionou beleza havendo o travamento do regitro. Porem como vou saber que o registro está travado, uma vez que quando
tento acessar pela segunda vez (por outro aplicativo) o programa trava no open da SQLQUERY e fica processando sem dar nenhum erro. Acho que o modo de bloqueio está como WAIT. Como resolver isto?
28/08/2004
Vinicius2k
Realmente a transação deve estar com o WAIT ativado, pq é o default do driver do Interbase...
Altere o parametro ´WaitOnLocks´ da TSQLConnection para ´False´, que deve resolver o problema, levantando a exceção imediatamente, caso o registro esteja travado...
Eu raramente uso travamentos, então, tenho conhecimento das instruções, mas não quase não uso na prática... nunca achei necessário dentro do contexto das minhas aplicações e da forma como trabalho as transações, mas cada caso é um caso, e não me cabe questioná-lo, mas sugiro que vc leia este artigo, que é fantástico...
http://www.comunidade-firebird.org/cflp/downloads/CFLP_T032.PDF
T+
Clique aqui para fazer login e interagir na Comunidade :)