Para nosso teste usamos ZeosLib. Por padrão o ZeosLib também opera no modo Auto-Commit, ou seja, cada comando é executado no contexto de uma transação. Não mostraremos aqui como conectar ao PG usando Zeos, pois isso já foi apresentado no post Lazarus - Conectando PostgreSQL com ZeosLib. Vejamos o primeiro teste. A unit Dateutils deve ser incluida na cláusula uses para poder usar a função
MilliSecondsBetween(). dbBanco é um ZConnection, dmDados é um Data Module e queCidade uma ZQuery.
var i: integer; a, b: TDateTime; begin dmDados.queCidade.SQL.Clear; dmDados.queCidade.SQL.Add('insert into cidade values (:id, :nome)'); a := time; for i := 1 to 5000 do begin dmDados.queCidade.ParamByName('ID').Value:= i; dmDados.queCidade.ParamByName('NOME').Value:='SANTAREM'; dmDados.queCidade.ExecSql; end; b := time; ShowMessage(IntToStr(MilliSecondsBetween(b,a))); end;
Neste primeiro código o tempo médio de inserção das 5.000 linhas foi de 11,6 segundos. Alteramos então nosso código para que todas as linhas fossem inseridas dentro de uma única transação. Para isso chamamos StartTransaction antes de iniciar os INSERTs. Observe o código abaixo.
var i: integer; a, b: TDateTime; begin a := time; dmDados.queCidade.SQL.Clear; dmDados.queCidade.SQL.Add('insert into cidade values (:id, :nome)'); dmDados.dbBanco.StartTransaction; for i := 1 to 5000 do begin dmDados.queCidade.ParamByName('ID').Value:= i; dmDados.queCidade.ParamByName('NOME').Value:='SANTAREM'; dmDados.queCidade.ExecSql; end; dmDados.dbBanco.Commit; b := time; ShowMessage(IntToStr(MilliSecondsBetween(b,a))); end;
Neste caso o tempo médio de execução do código foi de 2,9 segundos. Um ganho de tempo considerável em relação à execução em modo padrão.
Fizemos também um teste usando TZUpdateSQL, implementado de acordo com o post citado acima. O código é apresentado em seguida e o tempo médio de execução foi de 3,8 segundos. Um desempenho um pouco pior do que o teste anterior.
var i: integer; a, b: TDateTime; begin a := time; dmDados.queCidade.Open; dmDados.dbBanco.StartTransaction; for i := 1 to 5000 do begin dmDados.queCidade.Insert; dmDados.queCidade.FieldByName('ID').Value := i; dmDados.queCidade.FieldByName('NOME').Value:='SANTAREM'; dmDados.queCidade.Post;; end; dmDados.dbBanco.Commit; b := time; ShowMessage(IntToStr(MilliSecondsBetween(b,a))); end;
Estes teste foram feitos em Windows e servidor de BD e cliente rodando na mesma máquina. Certamente se você executar esses testes em outro ambiente, os tempos serão diferentes, mas comparativamente você deverá chegar à mesma conclusão.
Sabe-se que uma falha no sistema, enquanto uma transação estiver ativa, causa a execução de um ROLLBACK pelo SGBD, fazendo com que todas as atualizações feitas a partir do BEGIN sejam canceladas. Portanto, use esta recomendação com cautela e bom senso. Longas transações ativas estão sujeitas a perdas de dados muito maiores que transações curtas, em caso de falhas no sistema.
Atualizado em 28/09/2010.
13 comentários:
Professor, interessante este artigo sobre transação usando ZeosLib e PGSql.
Estou tentando usar o mesmo conceito usando SQLdb e MySql, porém não tenho sucesso, é como se a transação não tivesse sido inicializada. O sr. sabe me dizer se é possível?
No SQLdb tem o SQLTransaction. É ele que chama o StartTransaction e o Commit. Fiz o teste aqui e funcionou.
Ok, Obrigado.
No meu caso estou usando Linux. Você conhece algum caso? A versão de Lazarus que estou usando pode influenciar nessa questão?
Estou usando a versão 0.9.29 do Lazarus. E penso que não teria diferença no caso de ser Linux.
Valeu Professor, obrigado pela força.
Professor, quero aproveitar, e parabenizá-lo pela iniciativa. Eu também estou começando a minha aventura com a Lazarus, e vejo bastante futuro com esse. E os seus artigos estão sendo de grande valia para mim, e pretendo no futuro dar minha parcela de colaboração.
Até mais, obrigado.
Obrigado pelo comentário. Quanto mais pessoas usarem o Lazarus, maiores serão as chances de seu crescimento.
Oi professor, bom dia!
Me parece que no windows mobile a dll sqllite não é muito confiável, pois
em um mesmo aplicativo, estava funcionando sem problemas, porém sem nenhuma alteração passou a não conectar mais a base de dados.
Teria alguma informação sobre essa situacao?
Eu também tive dificuldades com a dll no WM 6. No WM 5 está funcionando bem. Nesse link http://www.parmaja.com/downloads/sqlite3-3.7.0.1-wince-arm.zip
Eles dizem que tem uma nova versão da dll. Seria o caso de fazer testes. Eu não tive tempo de fazer isso.
Caro Professor
Em um sistema que desenvolvi, em algumas situações precisei controlar as transações manualmente, pois eu necessitava gravar dois blocos de informações, e caso o segundo falhasse, o primeiro deveria ser revertido. Ótimo, criei uma rotina com TRY EXCEPT END, com StartTransaction, Commit e RollBack e setei o autocommit do ZConnection para false. Porém quando executava a rotina recebia um erro mais ou menos assim: "Cannot perform this operation in non autocommit connection".
Após pesquisar no site do Zeoslib, encontrei a informação que eu precisava. Lá eu li que eu não precisava usar o starttransaction, que este era chamado automaticamente, e que eu precisaria apenas do commit ou rollback. Testei e funcionou perfeito, até simulei um erro para confirmar que o rollback também funcionava, e funcionou.
Uso Lazarus 0.9.31 com Zeos 7.0 ambos do SVN.
Gostaria de aproveitar para parabenizá-lo pelo blog e pela divulgação do Lazarus.
Mantenho um site com informações, tutoriais, artigos, etc. para desenvolvimento de sistemas para WEB com Lazarus (lazarus-cgi.co.cc) todo feito em Lazarus, e gostaria de colocar um link do seu blog por lá. Caso ache a ideia interessante, me informe por favor [é gratis :)].
Abraço
Rafael Tuim Elias
Estava com problemas no desenvolvimento de uma apliação e sua explicação foi de grande valia.
Muito obrigado.
Olá Professor!
Vi nos comentários que você utilizou SQLite com Windows Mobile 5 e 6 (WinCE). Estou desenvolvendo um projeto aberto que utiliza ZeosLib e estou pensando em adicionar suporte a Windows CE a ele. Pergunto: Você utilizou ZeosLib com Lazarus para isso?
Oi Fábio
ZeosLib não funcionou para WinCE. Usei TSQLite3Dataset da unit sqlite3ds. Você pode ver como eu fiz em http://professorcarlos.blogspot.com/2010/03/lazarus-criando-uma-aplicacao-para.html. Fiz com DBF também: http://professorcarlos.blogspot.com/2010/08/lazarus-wince-com-dbf.html
Postar um comentário