You are on page 1of 10

Trabalhando com Transaes

Trabalhando com Transaes


Introduo
Resumo: Quase tudo que acontece num banco de dados interbase, acontece num contexto de uma transao. Transaes so o corao de qualquer aplicao cliente/servidor bem implementada. Com IBO voc tem 100% de visibilidade e controla tudo o que acontece com transaes nas suas aplicaes. Com isso vem a responsabilidade de entender como usar transaes. Se voc comea a usar Interbase e antes usava banco de dados desktop como Paradox, dBase e Access, ento o uso de transaes pode ser um pouco confuso para voc. Sistemas Desktop usam a estratgia de travar registros para prevenir que usurios atualizem registros que esto sendo usados por outros usurios. Lidar com travamentos pode ser bastante complicado e confuso em qualquer coisa nos banco de dados mais simples. Isto especialmente verdadeiro se voc quer fazer muitas alteraes e ou voc grava todas ou no grava nenhuma. Isto uma das coisas que as transaes fazem facilmente.

Bsico sobre Transao


A forma mais fcil de entender o conceito de transaes quebr-lo em trs partes distintas ou aspectos: Explicita, fsica e lgica. Ser muito importante que voc conhea estes aspectos porque eles sero freqentemente mencionados no restante deste documento.

Transaes Explicitas.
O aspecto em que a maioria das pessoas familiar a transao Explicita. Que quando o desenvolvedor explicitamente toma controle da transao. Isto feito chamando os mtodos: StartTransaction, Commit e Rollback. Isto permite ao desenvolvedor ter o controle explicito das suas transaes mas tambm o impede de saber tudo o que esta acontecendo para poder acompanhlo. A propriedade InTransaction diz se uma transao explicita foi inicializada ou no. No IBO transaes explicitas funcionam exatamente como no BDE, ento no haver problemas srios se voc quiser continuar trabalhando como fazia (desde que voc estava fazendo as coisas certas).

Transaes Fsicas.
Transaes fsicas ficaram escondidas no BDE, mas o IBO as exps totalmente. IBO automaticamente inicia uma transao fsica quando necessrio. A transao fsica representa a existncia atual de uma transao no servidor e a presena de um handle p/ a transao no cliente. A propriedade Started mostra se a transao foi iniciada ou no.

www.comunidade-firebird.org 1/1

Trabalhando com Transaes A partir do momento que uma transao fsica iniciada, interbase ativa um contexto que protege esta transao de outras alteraes processadas no banco de dados. E tambm providencia um contexto para gerenciamento de conflitos se dois usurios tentarem atualizar a mesma informao. A proteo de uma transao significa que o Interbase prevenido de executar garbage collection alem da mais antiga transao (OAT Oldest active transaction). Em troca, qualquer transao com alteraes de dados no confirmadas (commit), previne outras transaes de executar outras alteraes nestes registros. Por esses dois motivos, transaes fsicas no devem ser mantidas abertas desnecessariamente por longos perodos de tempo. IBO tem diversos mecanismos para termos certeza que uma transao fsica somente ser mantida aberta pelo tempo absolutamente necessrio. Na maioria dos casos, IBO toma total controle das transaes fsicas p/ voc. Mais adiante discutiremos mais sobre OAT (Oldest active transaction).

Transaes Lgicas
As transaes lgicas tem por aspecto fazer com que instrues com alteraes de dados ou metadata (alteraes, incluses, etc.) sejam enviados ao servidor. Isto que define se uma unidade de trabalho ser confirmada ou descartada como um todo. Assim que o dataset entre no estado de edio, ou uma instruo SQL envolvida em uma operao de DML (Data Manipulation Language) ou DDL (Data Definition Language) executada com sucesso, uma transao lgica est presente. A propriedade TransactionIsActive mostra se uma transao lgicas esta presente ou no. Uma transao lgica termina quando um lote de trabalho ou confirmada (commit) ou descartada (rollback) usando qualquer um dos mtodos que o acompanham. O aspecto lgico distinguido dos outros porque possvel para uma transao explicita ser iniciada chamando o mtodo StartTransaction sem uma transao lgica existir. Se o usurio no fez qualquer alterao, no existe uma transao lgica apesar de uma explicita estar presente. muito til saber quando o usurio fez alguma alterao, ou estar p/ fazer, apesar da presena de uma transao explicita. Se nenhuma transao lgica esta presente, no faz diferena se Commit ou RollBack chamado para terminar uma transao fsica, desde que nenhuma alterao esta pendente para se preocupar. Em muitos casos, a transao fsica termina quando a fsica termina, mas no sempre.

Uma Transao est em Progresso?


A propriedade Started mostra se existe ou no uma transao fsica alocada. Uma transao fsica deve ser iniciada apenas para mostrar os dados pela query. Ela ser iniciada automaticamente p/ voc pelo IBO sempre que necessrio. Sob certas circunstancias IBO tambm finaliza transaes fsicas.

www.comunidade-firebird.org 2/2

Trabalhando com Transaes A propriedade TransactionIsActive mostra houve ou no uma alterao confirmada (post) ou se uma alterao est pendente para o componente de transao. Em termos lgicos uma transao comeada no momento em que o dataset entra em um estado onde uma condio de alterao existe. Se aquela mudana cancelada e nenhuma outra mudana foi confirmada ento a transao lgica no mais ativa ou "iniciada ". Uma vez uma alterao confirmada a transao ento ativa at aquela mudana ser ou confirmada (commit) ou descartada (roll back). A propriedade InTransaction mostra se voc chamou ou no o mtodo StartTransaction para comear uma transao explcita. Comeando a transao explcita suspender o AutoCommit se ele tiver sido configurado. O AutoCommit retoma depois da transao explcita terminado. Isto acontece quando Cometa, CommitRetaining, Rollback, RollbackRetaining, Refrescam (), Feche, etc. foi chamado causando um cometa ou rollback para acontecer. SavePoint no reajusta o comportamento de AutoCommit como no considerado um fim para a transao embora faa todas as mudanas quele ponto permanente. O Inicio de uma transao explcita suspender o comportamento AutoCommit se isso foi fixado como true. Comportamento AutoCommit retomar depois que a transao explcita for terminada. Isto acontece quando Commit, CommitRetaining, Rollback, RollbackRetaining, Refresh(), Close, etc. foram chamados causando um commit ou rollback. SavePoint no reseta o comportamento AutoCommit como no considerado um fim da transao embora faa todas as mudanas quele ponto permanente. Assim, para responder esta pergunta, depende de que aspecto da transao que voc quer saber. Se voc precisa saber que se h uma transao fsica em andamento use a propriedade Started, para verificar uma transao lgica use a propriedade TransactionIsActive e para verificar uma transao explcita use a propriedade InTransaction.

Fechando uma Transao


Com o primeiro Prepare de uma query associada a uma transao, uma transao fsica automaticamente iniciada. Debaixo da maioria das circunstncias IBO garantir que a transao fsica no ficar aberta muito tempo. Se voc sentir a necessidade de garantir que uma transao no ficar aberta muito tempo, aqui est alguns modos que a transao fsica pode ser fechada. Os seguintes mtodos dos componentes TIB_Transaction ou TIBODatabase fecharo a transao fsica. Close; Commit; Rollback; Refresh( CommitChanges: boolean ); ChangeIsolation( NewIsolation: TIB_Isolation; CommitChanges: boolean ); Pause/Resume;

www.comunidade-firebird.org 3/3

Trabalhando com Transaes Quando Close chamado, ele tentar dar um Commit se AutoCommit for true; caso contrrio, Rollback ser executado. Se uma exceo acontece durante o Commit ele prosseguir e chamar Rollback ao invs. Uma chamada a Close tambm fecha todos os datasets associados com a transao. Se um objeto de Transao ativa for destrudo, Close ser chamado no destructor. Chamando Commit ou Rollback causa a o termino da transao fsica e cada dataset executa de acordo com sua prpria setagem para CommitAction. Para datasets nativos do IBO a ao padro fechar. Para os componentes TDataset a ao padro ficar aberto mas invalidar o cursor se um ainda estiver aberto (i.e., registros unfetched permanecem no servidor). Se havia um cursor aberto, o dataset dar refresh depois que a transao terminar para estabelecer um cursor novo. Refresh essencialmente o mesmo que chamar Commit ou Rollback, Exceto que fora todo o datasets dar refresh junto com o fim da transao fsica, Apesar do que cada propriedade CommitAction de cada dataset seja setada. ChangeIsolation quase igual a Refresh, exceto que ele permite mudar o isolamento usado pela transao. Voc no pode mudar a propriedade de Isolamento diretamente enquanto uma transao est ativa. Esta funo lhe permite dar refresh na transao e mudar seu Isolamento durante o curto perodo que a transao esta inativa. Os mtodos Pause/Resume permitem ao desenvolvedor parar uma transao sem fechar todo os datasets associados e essencialmente congelar a aplicao at que o usurio esteja pronto para voltar a trabalhar. Pause efetua o congelamento e Resume reativa a transao. Isto til em casos onde um grande dataset exigiria para o sistema constantemente dar refresh para manter o dataset aberto e no manter uma transao fsica aberta muito tempo. CommitRetaining, RollbackRetaining e SavePoint no do reset na transao fsica.

AutoCommit e StartTransaction
Se Autocommit true ento uma vez que o datase grava(post) suas alteraes estas so fisicamente commitadas no servidor atravs da chamada interna ao mtodo SavePoint. A propriedade AutoCommit no deveria ser mal interpretada como um modo do IBO de automaticamente assegurar que commits esto ocorrendo, como para prevenir que uma transao fsica fique aberta muito tempo. Enquanto AutoCommit ajuda manter transaes curtas, ele prprio no uma garantia. O mecanismo de administrao de OAT do IBO independentemente executa commits automticos para ter certeza uma transao fsica no mantida desnecessariamente aberta mais que o necessrio. Chamando o mtodo StartTransaction temporariamente suspende o comportamento AutoCommit at um "fisico" commit ou rollback for chamado. Quando Autocommit suspenso, mudanas gravadas(post) permanecero em um estado no confirmadas (uncommitted) e capaz ser desfeito(rollback) se necessrio.

www.comunidade-firebird.org 4/4

Trabalhando com Transaes Resumindo esta situao, embora AutoCommit seja true, se voc est em uma transao explcita pelo chamado a StartTransaction, uma vez que as alteraes sejam gravadas (post) ento uma transao lgica permanecer ativa at que Commit, CommitRetaining, Rollback ou RollbackRetaining, etc. for chamado. Ento, neste momento a transao lgica e explcita terminar. Se chamar Commit ou Rollback ento a transao fsica tambm terminar. Tenha cuidado desde que isto tambm pode fechar automaticamente qualquer datasets aberto (dependendo do CommitAction fixado do dataset).

Isolamento da transao
Este tpico discute isolamento de transao. Cada seo neste tpico lista uma srie de passos para demonstrar como diferentes configuraes do isolamento de transao impactam o usurio dos dados associado com uma transao particular. Para entender cada seo voc deve se referir ao tutorial de TransactionPausing distribudo com IBO - que tem dois datasets, cada associado com uma transao diferente mas cada que se referindo mesma tabela InterBase. Um dataset (query Controle) te permite especificar o isolamento da transao. Outro dataset (query AUTO) esta associada com a transap padro (default), o que significa que o isolamento da transao esta sempre setada p/ Ticommited. Cada dataset tem seu prprio grid p/ permitir tentar alterar os dados. Somente Alteraes confirmadas (commit) so visveis para outras transaes. 1 Tenha certeza que a transao da query controle esta setada como tiCommited. 2 Inclua ou altere um registro no grid da query Controle e confirme as alteraes (post) mas no clique em nenhum boto p/ commitar a transao. 3 Selecione a query Auto e clique no boto refreshAll no toolbar da query. Voc ver que todas as alteraes que voc fez no grid controle NO aparecem neste grid. 4 Clique no boto CommitRetainning ( que dar commit nas alteraes feitas no grid controle) e ento repita o item 3. Agora voc ver que as alteraes feitas no grid controle aparecero neste grid. NOTA: As alteraes apareceram no grid Auto porque o isolamento da transao esta setada p/ tiCommited, ento para ver as alteraes elas devem ser confirmadas (commit). Isolamento tiConcurrency tira um " Instantneo " quando a transao inicia. 1 Altere o isolamento da transao da query Auto p/ TiConcurrency. 2 Inclua ou altere um registro no grid da query Controle e confirme as alteraes (post) . Como a transao default esta setada p/ Autocommit, voc ver o resultado das alteraes sendo confirmadas (commit).

www.comunidade-firebird.org 5/5

Trabalhando com Transaes 3 - Selecione o qrid da query Auto e clique no boto RefreshAll da toolbar da query. Voc NO ir ver as alteraes que voc fez no grid controle aparecerem no grid Auto. Isto porque o Isolamento tiConcurrency tira um " Instantneo " quando a transao iniciada e ignorar qualquer alterao feita por outras transaes - mas verifique que este modo de Isolamento no parou as alteraes que foram feitas, voc apenas no as pode ver. (Voc est olhando velhas verses dos registros mantidas pelo Interbase para este propsito - que o que faz o Interbase multigenerational .) 4 Se voc confirmar (commit) ou desfazer (rollback) a transao e reabrir a query voce ver que as alteraes aparecero (Isto no acontecer se voc usar CommitRetaining). Isolamento tiConsistency bloqueia Alteraes 1 feche e reabra sua aplicao para sabermos em que estado ele esta. 2 Inicie a transao Controle e troque seu isolamento para TiConcurrency ento abra a query controle (selecione o grid da esquerda e ento clique no boto Open Query). 3 Abra a query Auto (selecione o grid da direita e ento clique no boto Open Query). 4 Tente excluir um registro na query Auto. Voc receber uma mensagem de exceo Lock Conflict.

Isto deveria destacar por que tiConsistency deve ser usado com grande cuidado. Ele travar TODOS os registros selecionados pela transao e prevenir mudanas para quaisquer destes registros mesmo se voc no tivernenhum uso para eles. Assim se voc executa um " SELECT * FROM TABLE "; ento voc travou TODOS os registros da tabela o que geralmente um efeito indesejvel.

Revisado para IBO4

Pausando a transao
Por causa dos problemas potenciais causados por deixar uma transao fsica aberta muito tempo, IBO prov vrias capacidades embutidas para minimizar o uso de transaes fsicas e tambm vrios mtodos para lhe permitir ter controle preciso da situao. Este tpico discute como usar o processamento Pause/Resume agora disponvel com o TIB_Transaction e se refere ao cdigo do projeto tutorial do TransactionPausing distribudo com IBO. A idia atrs deste conceito interromper uma transao (parar a transao fsica/servidor (physical/server)) quando no estiver realmente em uso, sem limpar todos os datasets associados, e ento permitir retomar (resume) a transao quando o usurio deseja comear ativamente a usar novamente os dados.

www.comunidade-firebird.org 6/6

Trabalhando com Transaes Isto realmente o mesmo que a funo TIB_Transaction.Refresh, mas dividido em duas partes. Parte 1 (Pause) fecha a transao fsica sem notificar o datasets, Parte 2 (Resume) cria uma transao nova e da refresh no datasets associado. Na aplicao de demonstrao voc achar um timer que inicia a funo seguinte (o timer fixado em 1 segundo para o que a demonstrao pretende, eu sugeriria que em uma aplicao real o timer devesse ser fixado em um minuto ou at mais longo).

procedure TTransactionMainForm.TransactionTimerTimer(Sender: TObject); begin UpdateTransactionList; CheckTransactions; end; Voc pode ignorar a funo 'UpdateTransactionList' uma vs que ela simplesmente mantem uma lista das transaes no rodap do form. O que somente necessria para demonstrao.

Pause Na procedure CheckTransactions voc verificar o processo atual introduzido para interromper transaes quando eles tm muito mais tempo que desejado. Esta funo grandemente simplificada do que voc pode usar em uma aplicao real, mas deve lhe dar uma idia do que precisa ser feito. A seguir uma descrio da funo

procedure TTransactionMainForm.CheckTransactions; var i: integer; iList: TList; iTran: TIB_Transaction; OAT: TDateTime; PauseEnabled: boolean; begin iList := TIB_Session.DefaultSession.Session_Transactions; {TIB_Session.DefaultSession d (e somente) acesso sesso default para o processo principal. A vida fica mais complicada em uma aplicao multi- threaded mas isso um assunto para outra demonstrao. O componente de TIB_Session mantm uma lista de todas as transaes para a sesso num TList chamado Session_Transactions. }

TransactionStateGrid.RowCount := iList.Count + 1; OAT := 0; PauseEnabled := true; for i := 0 to iList.Count - 1 do begin www.comunidade-firebird.org 7/7

Trabalhando com Transaes iTran := TIB_Transaction(iList.Items[i]); if OAT < iTran.TimeActive then OAT := iTran.TimeActive; {Acima, eu asseguro que OAT representa o TimeActive para a transao que esta ativa a mais tempo. TimeActive devolver 0 se a transao no esta ativa, caso contrrio TimeActive a diferena entre agora e o tempo que transao foi iniciada (LastStarted). Tambm veja LastStopped para o tempo a transao teve sua ultima parada.}

if iTran.IsPauseDisabled or iTran.IsPaused then PauseEnabled := false; {Acima eu asseguro que no tentarei pausar a se qualquer transao j estiver em pausa ou a pausa estiver desabilidata} end; if PauseEnabled and ((OAT * 86400) > 15) and {Acima estou conferindo o que eu quero pausar (nenhuma transao j foi pausada ou a pausa foi desabilitada), e que eu s tento pausar se a OAT tem mais que 15 segundos. Obviamente em uma aplicao real esta durao provavelmente seria fixada em 15 ou 30 minutos (ou o que for apropriado a uma aplicao em particular).} (((SysUtils.Now - FLastActivity) * 86400) > 15) then begin {Acima uma verificao especial para ver se o usurio usou o form ativamente nos ltimos 15 segundos (em uma aplicao real este tempo provavelmente seria de 5 ou 10 minutos). Esta verificao para tentar evitar que o processamento da pausa possa interromper o usurio no meio da digitao. Veja a procedure DoAppMessage (definida para Application.OnMessage), onde FLastActivity atualizado ao tempo atual a toda atividade do teclado ou do mouse. }

for i := 0 to iList.Count - 1 do begin TIB_Transaction(iList.Items[i]).Pause( false ); {Acima a chamada ao Pause, com o false indicando que qualquer alterao ser descartada (rollback)} end; PostMessage( Handle, WM_APP + 1, 0, 0 ); Em lugar de segurar a resposta para a mensagem do timer eu gravo (post) uma mensagem de volta nesta janela que resultar na apresentao de um form modal - veja a procedure ShowPauseMessage. } end; end;

Resume Uma vez voc interrompeu uma transao importante impedir que o usurio tente interagir com os dados at a transao for reativada(resume). Qualquer tentativa para interagir com dados em uma transao pausada resultar em uma exceo "Transaction Paused " o que no muito ruim mas no www.comunidade-firebird.org 8/8

Trabalhando com Transaes momento voc pode receber tambm vrias mensagens "Cursor Unknown" que podem confundir o usurio. Eventualmente pode ser possvel impedir que estes erros inesperados venham a acontecer, mas mesmo assim somente realmente apropriado assegurar o que visualmente bvio para usurio que , os dados no esto disponveis no momento. Na demonstrao eu fao isto com a seguinte procedure... procedure TTransactionMainForm.ShowPauseMessage( var Msg: TMessage ); var i: integer; iList: TList; begin Application.MessageBox( 'Transactions Paused. Click OK to Resume', 'Paused', MB_OK ); {Acima Eu mostro uma mensagem Modal. Que pode parao o precessamento ate que o susuario clique no boto OK. Isto previne que o usurio no esta tentando mexer nos dados at que a mensagem for mostrada} iList := TIB_Session.DefaultSession.Session_Transactions; TransactionStateGrid.RowCount := iList.Count + 1; for i := 0 to iList.Count - 1 do begin TIB_Transaction(iList.Items[i]).Resume( true ); {Acima ns chamam Resume(true) que resulta em todos os datasets serem atualizados (refresh). Voc poderia chamar Resume(false) quando voc no precisar que os datasets serem reiniciados/atualizados (restarted/refreshed) (e neste caso eles sero fechados) - talvez voc esteja fechando o form ou algo parecido. seguro chamar Resume at mesmo quando a transao no est em pausa uma vez que simplesmente ele ser ignorado. } end; end;

DisablePause e EnablePause
Na maioria das aplicaes haver vezes quando voc no quer a transao seja pausada. Talvez voc tenha um relatrio ou um longo processo rodando que voc no quer que sejam interrompidos. Para fazer isso voc pode simplesmente usar os mtodos DisablePause e EnablePause do TIB_Transaction. Na aplicao de demonstrao eu uso uma simples checkbox para prevenir a pausa, mas na sua aplicao rela voc pode ter algo como...

try Transaction.DisablePause; RunLongPocedure; finally Transaction.EnablePause; end; www.comunidade-firebird.org 9/9

Trabalhando com Transaes Verifique que voc tem que ter uma chamada a EnablePause para toda chamada para DisablePause ou a pausa no poder ser reativada. Por isto voc geralmente usar blocos de try/finally como mostrado acima. Se voc chama DisablePause quando a transao j esta em pausa voc receber uma exceo "Transaction Paused ".

Usando a aplicao de Demonstrao


Eu sugiro que voc experimente a aplicao de demonstrao, ambos com o checkbox 'Pause Enabled' marcado e desmarcado. Isto deve ajudar a destacar a importncia de encontrar um modo de assegurar que as transaes fsicas sejam regularmente resetadas - e os perigos de confiar em transaes '<default>'. O processamento Pause descritos acima apenas um modo de alcanar isto. Uma alternativa seria o simples uso do TIB_Transaction.Refresh (true/false) que resulta na transao fsica ser parada e reiniciada.

Aplicaes reais
Em uma aplicao real voce pode precisar levar em conta a possibilidade que um usurio deixar um dataset em um modo Edit (edit/insert). Em minha prpria aplicao eu uso dois valores de timeout diferentes. O menor interromper a transao se s est visualizando (PostPendingCount = 0). Eu uso um valor de timeout maior quando uma transao est editando (PostPendingCount> 0) e se este timeout alcanado eu desfao (rollback) as mudanas. (E tudo isso protegido por um timer de atividade para assegurar que eu no tento interromper um usurio no meio da digitao das suas alteraes.) Texto original Working with Transactions: Informao Tcnica Jason Wharton Computer Programming Solutions CPS - Mesa - AZ http://www.ibobjects.com
Artigo Original: http://www.ibobjects.com Jason Wharton jwharton@ibobjects.com
Comunidade Firebird de Lngua Portuguesa Visite a Comunidade em: http://www.comunidade-firebird.org

Traduo e adaptao: Cludio Sergio Gonalves claudio@clarosistemas.com.br

A Comunidade Firebird de Lngua Portuguesa foi autorizada pelo Autor do Original para elaborar esta traduo.

www.comunidade-firebird.org 10/10

You might also like