Você está na página 1de 12

TRANSAES EM FIREBIRD por Eugnio Reis

Qualquer pessoa que costuma freqentar fruns de discusso deve, em algum momento, ter-se deparado com uma pergunta recorrente, feita, especialmente, por aqueles que esto migrando de Paradox, dBase ou Access para um servidor de banco de dados como o Firebird: como fazer para travar um registro e impedir que dois usurios tentem alter-lo ao mesmo tempo? Seria uma pergunta fcil de responder se fechssemos os olhos para as implicaes que essa mudana pode trazer para o desenvolvimento da aplicao e at mesmo para o futuro profissional do programador que lanou a pergunta. A questo real seria: realmente necessrio travar um registro para impedir que dois usurios eventualmente tentem modific-lo ao mesmo tempo? E, para respond-la, necessrio pensar em outra questo: quais as implicaes de travar um registro de forma a impedir seu acesso concorrente? Vamos assumir que os leitores deste artigo usam o Delphi como ferramenta de desenvolvimento em conjunto com o Firebird. Por conta disso, nossos exemplos de cdigo iro ater-se basicamente s sutes IBX e dbExpress, com eventuais referncias ao BDE. Esse artigo tem uma abordagem muito conceitual. Ele foi intencionalmente escrito com o propsito de preencher uma lacuna de conhecimento de conceitos. A prtica, sem o alicerce de conceitos slidos, pode ser algo extremamente perigoso. Por isso, o foco principal ser nos conceitos. No final, passaremos a uma seo de estudos de casos de natureza mais prtica.

TRAVAMENTO Bem, a princpio necessrio estabelecer definies para o conceito de travamento de registro, que se dividem basicamente em dois tipos: pessimista e otimista. Ser pessimista, neste caso, significa que basta o usurio tocar o registro com a inteno de edit-lo para que o mesmo fique travado at o termino da operao. Otimista aquele que acredita que no haver acessos simultneos e s se preocupa em travar o registro na hora exata de gravar as modificaes. No caso de um travamento pessimista, significa que um usurio pode comear a edio de um registro, sair para tomar um cafezinho, conversar com os colegas e deix-lo l travado por muito tempo, o que no me parece ser uma boa idia. Se o travamento fosse otimista, ele, por definio, jamais estaria bloqueando outros usurios durante o tempo de edio dos dados. Os defensores do travamento pessimista poderiam dizer: tudo bem, ento a gente pensa em colocar um timer, de forma que quando se passarem n minutos ou segundos, ento o registro ser liberado automaticamente... Os defensores do travamento otimista poderiam redargir: de que serve investir em tanto controle se a possibilidade de coliso de registros remota e seus impactos praticamente inexistentes?.

TRANSAO Ok, ainda vamos retornar peleja entre os pessimistas e os otimistas, mas por enquanto vamos nos deter em entender mais algumas coisas. Primeiramente, vamos entender o conceito de transao. De uma forma simples e direta, uma transao qualquer operao de escrita em uma tabela em um banco de dados. Executar uma instruo UPDATE uma transao por si s, assim como da mesma forma o executar um DELETE ou um INSERT. Esse trio de comandos efetivamente altera o contedo dos dados dentro de uma tabela. Entretanto, comandos de alterao de estruturas de dados, como o ALTER TABLE, por exemplo, no so considerados transacionais. Controlar transaes significa ser capaz de definir regras de negcio e parmetros de comportamento para o funcionamento dessa escrita nas nossas tabelas de dados. Na verdade, o que realmente queremos fazer controlar mltiplas transaes, torn-las consistentes e dependentes entre si. Um exemplo clssico: transferncia de dinheiro entre contas. Uma conta corrente e uma conta de poupana. Se pretendermos, por exemplo, transferir 1.000 dlares de uma conta para outra, isso ir requerer diversas transaes no banco de dados. Vejamos: 1. 2. 3. 4. O saldo da conta corrente subtrado em 1.000 (UPDATE) criado um novo registro na sua tabela de extrato bancrio (INSERT) somado um valor de 1.000 ao saldo da sua conta de poupana (UPDATE) adicionado um novo registro no extrato de sua conta de poupana (INSERT)

Como podemos observar, a operao completa envolve 4 transaes, cada uma em uma tabela diferente. A pergunta : o que aconteceria com o dinheiro se o sistema conseguisse completar apenas as transaes 1 e 2 e deixasse de executar a 3 e 4 por falta de energia, por exemplo? Acho que pouca gente toleraria perder 1.000 dlares por causa de uma falha de um banco de dados, a situao hoje em dia est muito difcil para se abrir mo de qualquer dinheiro! Portanto, num caso de falha, o ideal que TODO o processo seja cancelado. o que chamamos de tudo ou nada.

INCIO E FIM DE UMA TRANSAO Toda transao tem um ponto de partida, normalmente uma chamada ao mtodo StartTransaction. O trmino da transao, por sua vez, definido por uma chamada ao mtodo Commit (confirma) ou Rollback (cancela). Portanto, em termos de cdigo, seria algo assim:

var t : TTransactionDesc; begin // dbExpress try t.IsolationLevel := xilREADCOMMITTED; SQLConnection.StartTransaction( t ); // Aqui seriam feitos os updates, deletes e inserts SQLConnection.Commit( t ); except SQLConnection.Rollback( t ); end; // IBX try IBTransaction.StartTransaction; // Aqui seriam feitos os updates, deletes e inserts IBTransaction.Commit; except IBTransaction.Rollback; end; end;

Existem diversas variantes dentro desses objetos, mas essa a idia geral. No caso do IBX, por exemplo, existe a idia do CommitRetaining, prtica muito comumente adotada. Em termos prticos, isso equivale a dar um Commit seguido de um StartTransaction, o que deixa a aplicao num estado permanente de controle multi-transacional. Este um comportamento semelhante ao do IBConsole, por exemplo, e equivaleria a ter no BDE a opo SQL Pass Thru configurada para SHARED NOAUTOCOMMIT (neste caso, o StartTransaction dispensvel, pois sempre se est em contexto de multi-transao). Antes mesmo que seja feita a pergunta, aqui vai a resposta: havendo qualquer tipo de falha, seja no banco de dados ou na rede, por exemplo, a ao necessariamente um ROLLBACK automtico dos dados pendentes. O banco jamais ir optar por um COMMIT. Alis, neste quesito, tenha muito cuidado, porque o IBX, por exemplo, permite configurar a operao padro de encerramento normal (sem crash) da conexo do seu aplicativo como sendo um commit, o que pode ser bastante indesejvel.

LOG DE TRANSAES E CACHED UPDATES Existe algo que muita gente talvez no saiba, especialmente aqueles recm chegados do Paradox, dBase ou Access. Um servidor de banco de dados controla o processo de escrita nas tabelas de maneira bem distinta dos bancos mencionados. Enquanto que o dBase e o Paradox escrevem diretamente na tabela, sem nenhum tipo de processo intermedirio, servidores de bancos de dados no procedem dessa forma. As transaes so primeiramente registradas num local conhecido como log de transaes, para s depois serem registradas nas tabelas. Alguns bancos usam nomes diferentes, o Oracle chama de segmento de Rollback, por exemplo, mas a idia a mesma.

O importante : um Commit ir garantir a escrita no log de transaes. De tempos em tempos, o banco ir executar uma operao conhecida como Checkpoint, a qual efetivamente escreve na tabela. No necessrio preocupar-se em controlar o checkpoint. Por enquanto, s necessrio compreender a necessidade da existncia de um log de transaes. ele que garante que cada usurio possa ver os resultados das transaes nas tabelas antes mesmo que elas estejam gravadas de fato. E, uma vez que tenham recebido COMMIT, as transaes esto garantidas. O log de transaes um recurso bastante caro do servidor. Para tornar o uso do log de transaes menos intenso e aliviar o uso do log, existe no ambiente cliente um recurso conhecido como Cached Updates (o nome tambm pode variar, o ADO, por exemplo, chama de Batch Optimistic, mas a idia basicamente a mesma). Quando um usurio abre um registro na tela e est fazendo alteraes com o recurso de Cached Updates, aquelas modificaes, por definio, esto sendo feitas apenas no programa cliente e o servidor de banco de dados no tomou conhecimento de nada do que est se passando. Somente quando for dado um ApplyUpdates (que manda todas as modificaes de uma s vez) ou emitido qualquer comando DML (update, delete ou insert) que o servidor ir providenciar a escrita no log de transaes. Conforme se pode concluir, o conceito de Cached Updates visa a otimizar o processo criando lotes de alteraes no cliente e no no log do servidor. O usurio edita os registros no seu computador e todas as alteraes so enviadas em um nico lote para o servidor. Dessa forma, s existe travamento de dados e uso do log de transaes no breve intervalo da execuo do primeiro ApplyUpdates at o Commit. Esta a razo pela qual normalmente se recomenda o uso de transaes explcitas em combinao com Cached Updates. Vale salientar tambm que com o uso de Cached Updates, caso no haja um contexto explcito de transao (um StartTransaction ou um CommitRetaining), ele ser criado automaticamente durante o tempo do ApplyUpdates. O esqueleto do cdigo ficaria mais ou menos desta forma:
// IBX try IBTransaction.StartTransaction; // Aqui seriam feitos os updates, deletes e inserts IBDataset1.ApplyUpdates; IBDataset2.ApplyUpdates; IBTransaction.Commit; except IBTransaction.Rollback; end;

Ou, caso se esteja trabalhando de forma similar ao IBConsole:


// IBX try // Aqui seriam feitos os updates, deletes e inserts IBDataset1.ApplyUpdates; IBDataset2.ApplyUpdates; IBTransaction.CommitRetaining; except IBTransaction.RollbackRetaining; end;

O exemplo acima poderia tambm ter algumas outras variantes, mas esta a idia geral. Poderamos ter 4 ou 5 tabelas sendo alteradas ao mesmo tempo. Cada ApplyUpdates se encarregaria de enviar ao servidor o lote de alteraes para cada uma delas. Em caso de haver alguma falha, todo o processo cancelado e ocorre um rollback no log de transaes. O uso de Cached Updates combinado com transaes otimistas tende a minimizar o uso do log de transaes pelo simples fato de que o servidor s toma conhecimento das alteraes por um breve espao de tempo, no precisando mant-las em aberto por muito tempo. Por default, sua aplicao Delphi trabalha sem Cached Updates, o que significa que qualquer transao estaria sendo feita diretamente no servidor. O gerenciamento do log de transaes uma das operaes mais caras para o servidor de banco de dados. Lembre-se sempre disso.

NVEL DE ISOLAMENTO Um outro conceito importante associado ao universo do controle transacional o nvel de isolamento dos dados. Conforme dissemos em relao ao log de transaes, possvel que vrios usurios estejam alterando dados numa mesma tabela. Quando se fala em isolamento, a primeira coisa da qual se deve tomar conhecimento que o Firebird distingue claramente dois tipos de processos: os de leitura (reader) e os de gravao (writer). Este o comportamento padro do FB em relao aos processos: Leitores no bloqueiam leitores (SELECT x SELECT) Leitores no bloqueiam gravadores (SELECT x UPDATE) Gravadores no bloqueiam leitores (UPDATE x SELECT) Gravadores bloqueiam gravadores (UPDATE x UPDATE)

Existem basicamente dois nveis principais de isolamento nos bancos de dados: Read Committed (Ler apenas dados gravados) Dirty Read (Leitura suja, pode ler dados pendentes) Em paralelo ao conceito de leitura, existe tambm a possibilidade de definir o modo de espera entre os processos. Basicamente, significa estabelecer se vamos esperar pelo trmino da transao concorrente ou vamos logo de imediato assumir que no podemos prosseguir com a alterao. Vamos ilustrar os conceitos atravs de uma situao prtica. PROCESSO A: alterou o registro n 2 de uma tabela e ainda NO deu o Commit Suponha que existe um processo B que quer ler os dados do registro 2. Se o modo de operao da sua conexo ou transao Read Committed, isso significa que o processo B vai enxergar os dados antigos do registro e no vai ver a alterao em andamento. Caso a opo selecionada fosse Dirty Read, o processo B poderia ler os dados ainda em andamento. O comportamento padro do Firebird Read Committed. Mais do que isso, o Firebird, em sua verso 1.0, NO permite leitura suja.

Vantagens e desvantagens? No difcil imaginar os transtornos que a leitura suja poderia trazer. O processo A poderia dar um rollback na transao e aquele status dos dados se tornaria completamente inconsistente. De toda forma, em nenhum dos casos o processo B poderia alterar os dados em andamento no processo A. Repetindo: dois processos no podem jamais alterar o mesmo registro ao mesmo tempo, isso no ocorre sob nenhuma hiptese. Se o processo B tentar escrever no registro em questo, ainda pendente no processo A, o Firebird retornaria um ERRO ou colocaria a outra transao numa fila de espera. J que falamos em fila de espera, vamos entender agora o que pode acontecer quando existe concorrncia de acesso a um mesmo registro e quais opes temos para controlar esse tipo de situao. O Firebird dispe de uma srie de parmetros de isolamento e resoluo de travamentos de registros, a saber: ISOLAMENTO concurrency. Este parmetro padro, no precisa ser especificado. Ele especifica que uma vez que um valor de um registro tenha sido lido por um query, aquele ser sempre o valor retornado em cada refresh at que se d incio a uma nova transao. Este comportamento conhecido como repeatable read ou leitura repetitiva, em bom portugus. Ainda neste tpico, vale destacar que quando um processo altera um determinado registro, ele no ter condies de voltar a enxergar o valor anterior dos campos antes de dar um rollback. Ele ir enxergar sempre o valor que ele mesmo estabeleceu. Exemplo: processo A altera o valor do campo Idade de 16 para 18 e ainda no emitiu commit nem rollback. Caso ele faa um SELECT naquele campo, ir obter 18, e no mais o valor original (a nica exceo fica por conta de triggers de atualizao). Somente depois de um rollback ele ser capaz de voltar a ver o valor original do campo (esta afirmao se aplica ao Firebird, mas caso disponha de Cached Updates no cliente, possvel ler o valor original, mas aqui se trata de recurso do cliente, no do servidor). consistency. Este parmetro perigosssimo e deve ser evitado. Ele bloqueia no apenas o registro alvo da transao, mas toda a tabela. Se at o momento temos desencorajado bloqueios pessimistas de registros, o travamento de tabelas algo que se mostrar ainda menos recomendvel. read_committed, rec_version. A combinao destes dois parmetros estabelece que o Firebird ir ler sempre a verso mais recente de registros devidamente gravados e confirmados (commit), eliminando o efeito de leitura repetitiva. Cada refresh na sua query poder trazer dados diferentes para a tela. Caso haja alguma alterao em andamento sendo executada por algum outro processo e que ainda no tenha recebido commit, ela ser ignorada. read_committed, no_rec_version. Esta configurao estabelece que o Firebird se tornar sensvel a outras alteraes em andamento. Neste caso, estaremos dizendo ao Firebird que gravadores iro bloquear leitores. Caso sua aplicao tente ler o registro e haja uma transao concorrente em andamento, ela ter que esperar pelo trmino do outro processo ou retornar um erro imediatamente, de acordo com o mtodo de resoluo escolhido.

RESOLUO wait. Caso haja uma transao concorrente em andamento, o processo que chegar por ltimo dever entrar numa fila de espera. Nenhuma mensagem de erro ser retornada, sua aplicao cliente ficar esperando pelo trmino da outra transao. No h opo de controle de durao do tempo de espera. nowait. Significa que, uma vez detectada uma situao de concorrncia por um determinado registro, no haver nenhum tipo de espera e uma mensagem de erro ser retornada imediatamente aplicao cliente. Este o padro do Firebird.

Em resumo, o Firebird, por padro, opera com concurrency e nowait (chamado de snapshot no IBX vide objeto IBTransaction). Para efeitos prticos, sugerimos que adote o modelo read committed, que a combinao de read_commited, rec_version e wait (ou nowait, dependendo da preferncia em termos de resoluo). Se quiser configurar diferentes parmetros, ter que recorrer a trs maneiras diferentes de faz-lo: 1. No caso da sute IBX, mais especfica para o Firebird / Interbase, procure o objeto IBTransaction e, na propriedade Params, escreva l o que deseja, sendo uma opo por linha. Exatamente por causa disso que se recomenda ter apenas um nico IBTransaction para toda a aplicao, a menos que se necessite de diferentes configuraes de transao dentro do mesmo aplicativo (situao rarssima e muito pouco recomendvel). Exemplos de utilizao: Params nowait read_committed no_rec_version 2. Outras sutes: se estiver usando o BDE, procure pela propriedade TransIsolation no objeto TDatabase; no ADO, procure pela propriedade IsolationLevel no objeto TADOConnection; no dbExpress, a propriedade IsolationLevel do objeto TTransactionDesc. 3. Use o comando SET TRANSACTION do Firebird. Exemplos: Efeito desejado Gravadores bloqueiam leitores e colocam em modo de espera Leitores no so bloqueados, mas se houver conflitos, no entrar em modo de espera Comando SET TRANSACTION WAIT READ COMMITTED NO RECORD_VERSION SET TRANSACTION NO WAIT READ COMMITTED RECORD_VERSION

Nossa recomendao, em particular, usar sempre o isolamento read_commited com rec_version e resoluo nowait, de forma que leitores jamais sero bloqueados por gravadores e gravadores jamais esperaro por gravadores, criando assim um ambiente com o mximo de disponibilidade dos dados e mnimo de bloqueio e espera.

Se quiser maiores detalhes sobre outros parmetros de transaes e sobre a sintaxe do comando SET TRANSACTION, consulte a documentao do Firebird 1.0 ou a do Interbase 6.0.

RESUMO GERAL OK, chegou a hora de colocar tudo junto. Vamos recapitular os conceitos: 1. A nica coisa que trava um registro, por definio, a operao de escrita. Existem algumas excees regra e podem ser especficas de cada plataforma de banco de dados. No caso do Firebird, por exemplo, um SELECT cria um tipo de bloqueio conhecido como shared lock. Embora esse tipo de bloqueio no impea que outros leitores e gravadores tenham acesso aos dados, impede que a tabela seja destruda com um DROP, por exemplo, at que todos os shared locks tenham sido liberados, o que normalmente acontece quando a query fechada ou quando dado um commit ou rollback. 2. A grande diferena entre um travamento otimista e o pessimista a quantidade de tempo pelo qual o registro fica travado. No otimista, ele fica o mnimo possvel. 3. As alteraes so registradas numa rea parte chamada log de transaes. 4. O travamento pessimista tende a saturar o uso do log pelo simples fato de forar o banco de dados a manter as transaes em aberto por um longo tempo. 5. No possvel, no Firebird, ler dados que ainda no receberam Commit e esto pendentes no log de transaes (leitura suja). 6. Um registro jamais poder ser alterado ao mesmo tempo por dois processos concorrentes no log de transaes. De posse dessas informaes, vm as perguntas: qual a melhor forma de proceder na prtica e onde conseguir exemplos de cdigo? Cada middleware vai oferecer recursos diferentes. Mas, em linhas gerais, a melhor sugesto adotar o travamento otimista como regra. Travamentos pessimistas tendem a arruinar a performance do banco de dados, a criar situaes de deadlock com mais freqncia, a gerar filas de espera por disponibilidade de dados e a aumentar a competio entre usurios. Quanto maior o nmero de usurios, mais transtornos o travamento pessimista tender a causar. uma relao simples e direta de causa e efeito: mais travamento = mais problemas.

ESTUDO DE CASO 1 CONTROLE DE ESTOQUE Existem grupos que defendem a necessidade de usar travamento pessimista para controlar a baixa de estoque. Mas vamos fazer um estudo da realidade de um estoque, verificar o os resultados e avaliar se ou no necessrio mudar de idia sobre travamentos pessimistas neste tipo de situao. Um dos procedimentos comuns pensar em travar o registro do produto na hora de atualizar o saldo para no ter inconsistncias no inventrio. Entretanto, qualquer pessoa que trabalhou no varejo sabe que invivel pensar em travamento pessimista. Se, por exemplo, um cliente chega num caixa de uma loja com o produto na mo, no h o que ser validado em termos de estoque. A prova da disponibilidade do produto est nas mos dele. O funcionrio, inclusive, dever ser capaz de efetuar a venda mesmo que o sistema esteja offline. Depois processada uma atualizao em lote e os saldos so ajustados. comum tambm fazer uma recontagem fsica de estoque a cada seis meses (os famosos saldos de balano) para evitar que discrepncias inevitveis causadas por fatores como furto, perda, deteriorao, etc se tornem muito grandes. Caso seja um funcionrio num balco e o cliente pergunte pela disponibilidade de um produto, o vendedor no pode bloquear registros, o ideal seria ele fazer uma reserva do mesmo, se necessrio. E, mesmo que o computador mostrasse saldo em estoque, poderia ter havido furto de mercadoria. No caso de controle de estoque, vale muito mais a pena investir em curva ABC de reposio de itens do que em travamento pessimista.

ESTUDO DE CASO 2 ALTERAO DE CADASTRO Tambm comum ouvir falar de alterao concorrente na ficha de cadastro de um cliente. Dependendo do caso, pode ser uma aberrao do ponto de vista logstico de uma empresa que dois usurios estejam alterando a mesma ficha de cliente ao mesmo tempo. Mas vamos considerar uma possibilidade real. Administradoras de carto de crdito, por exemplo, costumam fazer alteraes de cadastro em lote e no em tempo real. Caso um usurio legtimo e um mal-intencionado liguem ao mesmo tempo pra fazer uma alterao no cadastro, no h concorrncia. Elas so colocadas em fila e vai valer a que chegar por ltimo. Como medidas de segurana (alm das perguntas de praxe ao cliente), existem alertas automticos que so disparados se o nmero de alteraes cadastrais exceder um determinado nvel num certo intervalo de tempo.

ESTUDO DE CASO 3 RESERVAS Outro caso comum em companhias areas, mas que pode tambm acontecer em contextos menores da reserva de um item especfico: um determinado assento num vo, um carro preferencial para ser alugado, um inventrio de produtos usados. O inventrio de produtos usados me parece ser o mais ilustrativo pelo simples fato de que normalmente todos os itens so nicos e no h mais de uma cpia do mesmo produto em estoque. Suponha que seja um inventrio de micros usados, por exemplo. bem provvel que no haja dois micros exatamente do mesmo modelo com todos os acessrios iguais. Dessa forma, se um usurio est fazendo uma compra pela Internet, selecionou um modelo disponvel no inventrio e o colocou na cesta de compras, como proceder se outro usurio, tambm via Internet, selecionou o mesmo modelo e ambos esto com o mesmo micro na cesta de compras? Seria correto, neste caso, travar o registro do micro no inventrio e impedir que o outro comprasse? Digamos que 20 minutos seriam o tempo mximo para o cliente tomar uma deciso. Mas voc acha que o cliente se sentiria bem tendo que tomar uma deciso em 20 minutos? Suponha que depois de 15 minutos procurando, ele acha outro modelo mais adequado aos seus interesses e descarta o primeiro. Esses 15 minutos certamente seriam suficientes para fazer o outro cliente em paralelo desistir do produto. A pergunta crucial : a quem interessaria o travamento pessimista? Poderamos estar perturbando a paz do cliente, aumentando a possibilidade de perda de vendas e tambm colocando a nossa reputao em jogo, na medida em que essa concepo de sistemas causaria prejuzos ao andamento dos negcios.

ESTUDO DE CASO 4 NUMERAO SEQENCIAL Ok, vamos dar uma trgua ao travamento pessimista e apresentar uma situao em que ele muito bem-vindo. Situaes em que h a necessidade de gerar numeraes seqenciais que no podem conter furos, por exemplo, demandam a necessidade de travamentos pessimistas. Um exemplo tpico a gerao de nmeros de matrcula, de seqncia de Nota Fiscal ou de nmeros seriais de produtos. Nestes casos, a abordagem mais comum usar travamento pessimista, mas com reteno do registro por pouco tempo. A estratgia mais usada consiste em ter uma tabela com uma estrutura simples, normalmente com apenas duas colunas, uma contendo o identificador da seqncia e a outra contendo o ltimo nmero usado. Conforme o exemplo: ID_SEQ VARCHAR(10) POSICAO_ATUAL NUMERIC(12, 0)

Obviamente, os nomes e os tamanhos dos campos podero variar, mas a idia permanece a mesma. Usar um identificador para cada seqncia se torna mais do que conveniente quando existem vrias delas dentro do sistema. Alguns desenvolvedores que tentam controlar as seqncias na forma de coluna acabam se esbarrando exatamente no problema do travamento. Veja as ilustraes: Em coluna TALAO_01 502 Em linha ID_SEQ TALAO_01 TALAO_02

TALAO_02 143

POSICAO_ATUAL 502 143

Ainda no tivemos a oportunidade de trabalhar com um servidor de banco de dados que travasse apenas uma coluna especfica de um registro. Portanto, no caso da abordagem atravs de colunas, o travamento do numerador do Talo 01 inevitavelmente levaria tambm ao travamento do Talo 02. A situao se tornaria cada vez mais crtica quanto maior fosse o nmero de colunas, alm da evidente dificuldade de manuteno do sistema em caso de ser agregado mais um talo, por exemplo. No caso da criao de numeradores seqenciais organizados em linhas de uma tabela, ficamos livres dos inconvenientes mencionados. A forma exata como o travamento pessimista vai ocorrer depender, obviamente, da concepo de cada sistema. Em linhas gerais, o fluxo mais ou menos o seguinte: 1. Abre-se um contexto explcito de transao, caso ainda no esteja aberto. 2. Faz-se uma operao de UPDATE no numerador. Exemplo: UPDATE seq SET posicao_atual = posicao_atual + 1 WHERE id_seq = TALAO_02. Esta operao ir provocar o travamento imediato do registro. Qualquer outro programa na rede que tente realizar a mesma operao ter que esperar. 3. Faz-se a leitura do novo valor: SELECT posicao_atual FROM seq. Neste caso, o valor lido ser o recm atualizado. Outros processos que tentem ler o numeral podero esbarrar em duas possibilidades diferentes: 1) entrar em fila de espera; 2) ler o valor antigo. Entretanto, assumindo que todos os processos vo abordar a tabela da mesma forma (com um Update primeiro), ento no vou me preocupar com SELECTs feitos de outra forma. 4. O novo valor includo na tabela onde lhe convm: uma nova NF gerada, uma nova matrcula cadastrada, um nmero serial emitido. 5. Se a transao for fechada com sucesso, ser dado um COMMIT. Se falhar, ser dado um ROLLBACK e o incremento do numerador ser cancelado, voltando ao valor antigo. Em ambos os casos, a transao ser explicitamente encerrada e todos os travamentos sero liberados. Outros processos estaro livres para gerar novos valores seqenciais a partir deste momento.

O ponto mais crtico neste processo o tempo pelo qual o registro ficar bloqueado. preciso ter em mente que reter um determinado registro da tabela de nmeros seqenciais por um tempo demorado poder causar transtornos para outros usurios. Portanto, os alvos do travamento pessimista so a segurana e a consistncia, no o tempo de reteno dos registros, mas ocorre uma confuso muito grande na prtica por causa desse mal-entendido. Deve-se tambm procurar fazer com que todos os processos abordem as tabelas da mesma forma, na mesma ordem. Conforme citamos no caso do SELECT ser feito depois do UPDATE, uma inverso na ordem do processo pode levar a grandes confuses e deadlocks dentro do seu banco de dados. Portanto, se um processo usa primeiro um SELECT e depois um UPDATE, ento que a mesma regra seja vlida para todos. Para que fique ainda mais claro: o fundamental no a ordem em si, mas sim a utilizao de uma mesma sistemtica para todos.

CONSIDERAES FINAIS Fica aqui a mensagem: da prxima vez que estiver diante da afirmao de que o travamento TEM que ser, de forma obrigatria, pessimista, h 99% de chances de se estar diante de um tcnico ou de um gerente caprichoso, e no de um analista de sistemas com foco voltado para as regras de negcio. Travamentos pessimistas no so procedimentos execrveis, pelo contrrio, tm sua hora e momento de ser usados, conforme ficou demonstrado. A confuso se d quando so usados para resolver situaes que poderiam ter uma soluo mais elegante, tanto do ponto de vista tcnico quanto do ponto de vista do negcio da empresa. Por fim, respeitando as divergncias de opinio, a dinmica do conhecimento e o fato de que contribuies so sempre bem-vindas, deixamos o espao aberto para que qualquer pessoa que leu este artigo possa, se assim o desejar, apresentar situaes onde o travamento pessimista com uma longa possibilidade de espera e bloqueio de usurios seja a nica alternativa vivel, depois de ponderados todos os prs e contras. A manifestao das opinies pode ser feita no espao reservado para comentrios dentro deste site ou atravs do e-mail firebird@eugenio.com.br. Eugnio Reis consultor de desenvolvimento de sistemas cliente/servidor, distribudos e web com grandes bancos de dados (VLDB) para o Governo do Estado de Nova York, nos EUA. Possui as certificaes MCSE, MCSD, MCDBA, MCT, Oracle DBA e Delphi.

Artigo Original Eugnio Reis

firebird@eugenio.com.br

Comunidade Firebird de Lngua Portuguesa Visite a Comunidade em: http://www.comunidade-firebird.org

A Comunidade Firebird de Lngua Portuguesa foi autorizada pelo Autor do Original para divulgar este trabalho

Você também pode gostar