Conteúdo


Estratégias de Transação

A Estratégia de Alto Desempenho

Aprenda como implementar uma estratégia de transação para aplicativos de alto desempenho

Comments

Conteúdos da série:

Esse conteúdo é a parte # de # na série: Estratégias de Transação

Fique ligado em conteúdos adicionais dessa série.

Esse conteúdo é parte da série:Estratégias de Transação

Fique ligado em conteúdos adicionais dessa série.

Até o momento nesta série, você aprendeu como implementar três estratégias de transação:

  • A visualização Camada da API , adequada para aplicativos de negócios com uma camada de API com poucas divisões
  • A visualização Orquestração de Cliente , adequada para aplicativos de negócios com uma camada de API com mais dividida
  • A visualização Alta Simultaneidade , adequada para aplicativos que possuem uma alta carga de usuários simultâneos

Nesta parte final, apresentarei uma estratégia de transação que é útil para aplicativos com requisitos de altíssimo desempenho. Como a estratégia Alta Simultaneidade, a estratégia de Alto Desempenho envolve vantagens e desvantagens a serem consideradas.

As transações são necessárias para garantir um alto nível de integridade e consistências de dados. Mas as transações também são custosas; elas consomem recursos valiosos e podem diminuir a velocidade de processamento de um aplicativo. Quando você possui um aplicativo de alta velocidade no qual cada milissegundo conta, você pode manter a propriedades de ACID (atomicity, consistency, isolation, and durability) em alguma extensão implementando a estratégia de transação de Alto Desempenho. Conforme você verá neste artigo, a estratégia de Alto Desempenho não é tão robusta quanto as outras estratégias de transação, e ela não é a melhor opção para todos os casos de uso envolvendo aplicativos de alto desempenho. Mas há determinados momentos em que essa estratégia permitirá manter o tempo de processamento o mais rápido possível e ainda suportar algum grau de integridade e consistência de dados.

Transações Locais e Estruturas de Compensação

Do ponto de vista da persistência de dados, a forma mais rápida de executar uma operação de atualização do banco de dados é usar transações locais combinadas com procedimentos armazenados no banco de dados. As transações locais (às vezes referidas como transações do banco de dados) são transações que são gerenciadas pelo banco de dados em vez do ambiente do contêiner. Não é necessário codificar nenhuma lógica de transação em seu aplicativo (como por exemplo, a anotação @Transactional no Spring ou a anotação @TransactionAttribute no EJB 3).

As procedimentos armazenados são rápidos porque são pré-compilados e residem no servidor do banco de dados. Não são necessários para a estratégia de Alto Desempenho e sua efetividade e desempenho tem ocasionado alguns argumentos interessantes (consulte o link "Os Procedimentos Armazenados de Banco de Dados são Bons ou Ruins?" em Recursos). O uso de procedimentos armazenados pode reduzir a portabilidade do aplicativo, aumentar a complexidade e diminuir a agilidade geral. Mas, geralmente, são mais rápidos do que instruções SQL do JDBC com base em Java, e quando desempenho é mais importante que portabilidade e manutenção, eles são uma boa opção. Assim, você pode certamente usar qualquer estrutura com base no JDBC com SQL simples, se desejar.

Se as transações locais são tão rápidas, então por que todos não as usam? A principal razão é que, a menos que você use uma técnica como a passagem de conexão, você não poderá manter propriedades de transações ACID tradicionais. Com transações locais, as operações de atualização do banco de dados são tratadas como unidades individuais de trabalho em vez de um todo coletivo. Uma outra limitação das transações locais é que você não pode usá-las com estruturas de mapeamento relacional de objetos (ORM) tradicionais, como por exemplo, Hibernate, TopLink ou OpenJPA. Você estará restrito às estruturas com base em JDBC, como iBATIS ou Spring JDBC (consulte Recursos), ou sua própria estrutura de objeto de acesso a dados (DAO) personalizada.

A estratégia de Alto Desempenho é baseada no uso de transações locais. Mas espere — se o modelo de Transação Local não suporta propriedades ACID básicas, então como pode uma estratégia de transação com base neste modelo possivelmente ser uma boa estratégia? A resposta é que a estratégia de Alto Desempenho usa o modelo de Transação Local em conjunto com uma estrutura de compensação. Cada operação de atualização de banco de dados individual existe de forma independente, mas no evento de um erro, a estrutura de compensação garante que as transações individuais sejam revertidas, mantendo a atomicidade e a consistência.

A Figura 1 ilustra o que acontece quando você usa transações locais sem uma estrutura de compensação. Observe que, quando o terceiro procedimento armazenado falha, a unidade lógica de trabalho (LUW) é finalizada, e o banco de dados é deixado em um estado inconsistente com apenas duas das três atualizações aplicadas:

Figura 1. Transações locais sem uma estrutura de compensação
Transações locais sem uma estrutura de compensação
Transações locais sem uma estrutura de compensação

Com uma estrutura de compensação pronta, quando ocorre um erro, as transações bem-sucedidas são revertidas, resultando em um banco de dados consistente. Figura 2 ilustra o que acontece (de forma conceitual) quando o mesmo erro ocorre como na Figura 1. Observe que, assim que o procedimento armazenado retorna de forma bem-sucedida, ele é registrado na estrutura de compensação. Quando o terceiro procedimento falha, ele aciona um evento dizendo para a estrutura de compensação reverter tudo incluído neste escopo de compensação.

Figura 2. Transações locais com uma estrutura de compensação
Transações locais com uma estrutura de compensação
Transações locais com uma estrutura de compensação

Esta técnica é comumente referida como ACID relaxado. É uma solução de transação típica para casos de uso como transações de longa execução em uma arquitetura orientada a serviços usando Business Process Execution Language (BPEL) para coreografia do processo ou para uso de serviços da Web. Em tais casos, uma unidade de trabalho transacional pode demorar minutos, horas ou, em alguns casos, dias para ser concluída. É irreal assumir que você pode manter recursos por tanto tempo assim. Além disso, é difícil (e às vezes impossível) propagar uma transação entre determinadas plataformas heterogêneas ou sobre HTTP (como no caso dos serviços da Web).

O conceito de ACID relaxado também pode ser aplicado para transações de curta execução. No caso da estratégia de transação de Alto Desempenho, a duração da transação é medida em segundos, não em minutos. Entretanto, os mesmos princípios se aplicam — em situações de alto desempenho extremo você deseja maximizar a simultaneidade de bancos de dados e minimizar os tempos de espera e tempos de processamento. Além disso, você deseja estimular os meios mais rápidos possíveis para a execução de operações de atualização do banco de dados. Isso é conseguido por meio do uso de transações locais e procedimentos armazenados de banco de dados. A estrutura de compensação está lá apenas para auxiliar na ocorrência de um erro; ela não se envolve quando as coisas funcionam corretamente. A simultaneidade de bancos de dados está em seu máximo, as operações de atualização de banco de dados são executadas da forma mais rápida possível e na ocorrência de um erro, tudo é administrado para você pela estrutura de compensação. Parece perfeito, não é? Bem, infelizmente não é.

Trocas e Problemas

Muitas vantagens, desvantagens e questões estão associadas a esta estratégia de transação. Lembre-se, ela fornece a forma mais rápida possível para executar transações e ainda manter as propriedades ACID em algum grau. Você abandona o isolamento, a robustez e a simplicidade da transação. Você deve usar esta estratégia apenas se não puder obter o desempenho necessário usando uma das outras três estratégias descritas nesta série. As estruturas de compensação são complexas e arriscadas, seja construindo-as você mesmo ou usando uma das soluções de software livre ou comerciais (o que abordaremos um pouco mais adiante neste artigo).

Talvez, o maior problema associado a esta estratégia é a carência geral de robustez e consistência de dados que é típico da maioria das soluções com base em compensação. Como você não possui isolamento de transação, cada operação de atualização do banco de dados é tratada como uma unidade de trabalho individual. Portanto, uma outra unidade de trabalho pode entrar em ação nos dados em processo. Se ocorrer um erro durante a LUW, pode ser tarde demais para reverter as atualizações; ou, mais tipicamente, reverter a atualização pode causar problemas em cascata. Por exemplo, assuma que você esteja processando um pedido muito grande que excluirá o estoque desse item. Durando o processamento, um evento é disparado (porque o pedido é executado para o banco de dados durante a LUW) para enviar automaticamente uma mensagem para o fornecedor para estocar novamente esse item. Se ocorrer um erro durante o processamento do pedido, a estrutura de compensação reverterá a transação, mas o efeito do pedido (ou seja, a mensagem de reposição de estoque) já foi enviada ao fornecedor, resultando em um estoque desse item específico além do necessário. Se as propriedades de ACID tradicionais fossem mantidas, a mensagem do evento para reposição de estoque não teria sido enviada até que a LUW inteira do processo do pedido fosse concluída. Esse é apenas um dos muitos exemplos que ilustram como a inconsistência de dados pode ocorrer, mesmo quando as estruturas de compensação são usadas para manter a atomicidade da transação.

Determinadas situações ou tecnologias de negócios não prestam-se para a estratégia de transação de Alta Simultaneidade. Em particular, os cenários de processamento assíncrono estão em alto risco quando estruturas de compensação e ACID relaxado são usados. Em algumas circunstâncias, pode ser necessário negociar algum nível de desempenho para uma estratégia de transação com base em ACID mais lenta. Uma outra troca com esta estratégia é que você não pode estimular o uso de estruturas de persistência com base em ORM, o que necessita do modelo de transação Programático ou Declarativo. Isso não restringe você à codificação JDBC bruta; há várias estruturas com base em JDBC que você pode usar, incluindo iBATIS (uma estrutura de mapeamento SQL de software livre) e Spring JDBC. Ou você pode usar sua própria estrutura com base em DAO customizada. A restrição ORM pode exigir que você ainda aceite uma outra troca — seleção de capacidade de manutenção e tecnologia para melhor desempenho com o suporte a transações.

Embora você mantenha algum nível de consistência do banco de dados usando estruturas de compensação, um alto grau de risco está associado a esta estratégia. Erros podem ocorrer durante o processo de reversão de transação, deixando seu banco de dados em um estado inconsistente. Neste caso algumas operações de atualização do banco de dados podem ser revertidas enquanto outras não, às vezes necessitando intervenção manual para corrigir o problema. Por esta razão, aplicativos com poucas operações de atualização de banco de dados em uma única LUW são bons candidatos para esta estratégia de transação. Além disso, aplicativos usando esta estratégia geralmente não possuem o uso de entidades compartilhado dentro de LUWs intercaladas, significando que é raro para múltiplos usuários atuarem na mesma entidade (tal como conta, cliente ou pedido) ao mesmo tempo. Essas características reduzem a chance para resultados catastróficos ocasionados por inconsistência e falta de isolamento da transação.

Os aplicativos adequados para esta estratégia de transação específica são razoavelmente robustos, com erros ocorrendo de forma infrequente (com taxa de erro inferior a 10 por cento). A execução de compensação de transação é uma operação custosa e que consome tempo. Se você estiver constantemente revertendo suas operações de atualização de banco de dados, seu sistema perderá desempenho e provavelmente executará mais lentamente do que se você fosse usar uma das outras estratégias de transação. E quanto mais você necessitar executar atualizações compensatórias, maior o risco de inconsistências do banco de dados. Certifique-se de analisar sua taxa de erro antes de selecionar esta estratégia de transação.

O resto deste artigo descreve uma estrutura de compensação existente e mostra uma implementação simples usando uma solução customizada para ilustrar os conceitos que descrevi.

Estruturas de Compensação Existentes

Duas das estruturas de compensação estão disponíveis dentro da plataforma Java: o Serviço de Atividade J2EE para Transações Estendidas (JSR 95) e a Estrutura de Atividade de Negócios JBoss (consulte Recursos). Elas fornecem a lógica do registro, sistema de mensagens e acionador de compensação (mas não os próprios métodos de reversão de atualização). Como as estruturas de compensação descritas na barra lateral Mesmo Conceito, Problema Diferente , essas estruturas geralmente são associadas a transações de longa execução ou pedidos com base na Web e, dessa forma, são difíceis de usar com a estratégia de transação de Alto Desempenho. Como resultado, você mais provavelmente preferirá criar sua própria estrutura de compensação customizada quando estiver usando esta estratégia de transação.

Embora a especificação de Serviço de Atividade J2EE seja principalmente destinada para fornecedores de servidores de aplicativos, você pode aplicar os mesmos conceitos para sua própria estrutura de compensação customizada. Portanto, fornecerei a você uma breve introdução ao Serviço de Atividade J2EE nesta seção para que você compreenda como operam as estruturas de compensação.

O Serviço de Atividade J2EE para Transações Estendidas tem como base o Serviço de Atividade OMG (consulte Recursos). A especificação de Serviço de Atividade J2EE define um conjunto de interfaces e classes que coordenam e controlam a execução das ações dentro de uma atividade. Uma atividade é um conjunto de ações registradas (tais como operações de atualização de banco de dados). As atividades são controladas e coordenadas por um controlador, que é um protocolo que pode ser conectado, geralmente implementado como um componente de plug-in de terceiros. Cada atividade contém um conjunto de sinais (javax.activity.SignalSet), que envia sinais (javax.activity.Signal) para cada ação registrada. A Figura 3 mostra uma visualização conceitual do que acontece quando a compensação é usada:

Figura 3. Visão conceitual do Serviço de Atividade J2EE
Visão conceitual do J2EE
Visão conceitual do J2EE

As atividades devem ser registradas com o controlador (ou mais especificamente um componente do gerenciador de compensação dentro do controlador). Assim que uma atividade for concluída, um sinal é enviado (neste caso, ÊXITO ou FALHA) para o controlador. Se o controlador receber um sinal de ÊXITO de uma atividade, ele envia um sinal para o componente do coordenador (neste caso, PROPAGAR), desta forma invocando a próxima atividade. Observe na etapa 8 da A Figura 3 que um sinal de FALHA é enviado de volta ao controlador. Neste caso o controlador envia um sinal de FALHA para o coordenador, desta forma invocando as atividades compensatórias em ordem reversa. Embora não esteja representado na Figura 3, o controlador também monitora os sinais indo e voltando entre as atividades compensatórias e o coordenador para garantir que as atividades reversas também sejam concluídas com êxito.

Implementando uma Estrutura de Compensação Customizada

Escrever uma estrutura de compensação customizada parece ser uma tarefa duvidosa, mas ela não é excessivamente complexa — apenas consome tempo. Você pode implementar sua própria estrutura de compensação usando um código Java antigo e simples, ou usar técnicas mais elaboradas. Com o espírito da simplicidade, mostrarei um exemplo simples usando um código Java simples para que você compreenda o conceito; Deixarei a criatividade e diversão para você.

Se você usar uma estrutura de compensação de software livre, comercial ou customizada, você ainda deve fornecer o método, SQL ou procedimento armazenado a ser invocado para reverter as operações de atualização do banco de dados. Essa é uma outra razão pela qual eu prefiro usar procedimentos armazenados com a estratégia de Alto Desempenho. Eles são relativamente fáceis de catalogar, são autocontidos e tornam mais fácil identificar (e executar) o procedimento compensatório. Portanto, usarei procedimentos armazenados nos exemplos que estou prestes a apresentar.

Dessa forma, não incomodo você com detalhes desnecessários, simplesmente vou assumir que já tenho os seguintes procedimentos armazenados no banco de dados prontos para uso:

  • sp_insert_trade (insere um novo pedido de negociação de ações no banco de dados)
  • sp_insert_trade_comp (reverte uma inserção de negociação executando uma exclusão no banco de dados)
  • sp_update_acct (atualiza o saldo em uma conta para refletir uma compra ou venda de ações)
  • sp_update_acct_comp (atualiza o saldo em uma conta para o valor anterior à atualização mais recente)
  • sp_get_acct (obtém uma conta a partir do banco de dados)

Eu também não mostrarei as classes DAO usando o código JDBC CallableStatement , assim eu posso dar foco ao código que é mais relevante a esta estratégia. (Consulte Recursos para obter referências e o código para invocação de procedimentos armazenados usando JDBC linear). Como a implementação do coordenador de compensação customizada tende a variar um pouco e pode ser significativamente detalhada, mostrarei apenas a estrutura subjacente e fornecerei comentários sobre como preencher o restante do código de implementação.

Dependendo de como você implementar a estratégia e qual técnica usar para atualizações compensatórias, as anotações ou lógica a serem usadas para controle das operações de reversão de atualização podem estar na camada de API do aplicativo ou sua camada DAO. Para ilustrar as técnicas para implementação da estratégia de Alto Desempenho, usarei um simples exemplo de negociação de ações em que a lógica para coordenação do escopo de compensação reside na camada de API do aplicativo. Neste exemplo, duas atividades associadas a uma negociação de ações: insira a negociação de ações no banco de dados (atividade 1), e atualize o saldo da conta para refletir a negociação de ações (atividade 2). Ambas as atividades são implementadas em métodos separados usando transações locais e procedimentos armazenados. O coordenador de compensação customizada (CompController) é responsável por gerenciar o escopo de compensação e reverter as atividades se ocorrer um erro.

A Lista 1 ilustra o método de negociação de ações sem o uso das transações de compensação. A visualização AcctDAO e na TradeDAO referidas pelo método processTrade() contêm a lógica JDBC para execução dos procedimentos armazenados listados anteriormente. Não abordarei essas classes para ser mais breve.

Lista 1. Exemplo de negociação de ações sem transações de compensação
public class TradingService {

   private AcctDAO acctDao = new AcctDAO();
   private TradeDAO tradeDao = new TradeDAO();

   public void processTrade(TradeData trade) throws Exception {

      try {
         //adjust the account balance
         AcctData acct = acctDao.getAcct(trade.getAcctId());
         if (trade.getSide().equals("BUY")) {
            acct.setBalance(acct.getBalance()
               - (trade.getShares() * trade.getPrice()));
          } else {
            acct.setBalance(acct.getBalance()
               + (trade.getShares() * trade.getPrice()));
          }

          //insert the trade and update the account
          long tradeId = tradeDao.insertTrade(trade);
          acctDao.updateAcct(acct);

      } catch (Exception up) {
         throw up;
      }
   }
}

Observe na A Lista 1 a ausência do gerenciamento de transação (nenhuma anotação ou código de transação programático ou declarativo). Se ocorrer um erro durante o método updateAcct() , a negociação inserida pelo método insertTrade() não será revertida, resultando em um banco de dados inconsistente. Embora este código seja rápido, ele não suporta as propriedades de transação ACID.

Para aplicar a estratégia de transação de Alto Desempenho, primeiro é necessário criar (ou usar) uma estratégia de compensação para controlar as atividades e revertê-las caso ocorra um erro. A Lista 2 ilustra um simples exemplo de um coordenador de compensação customizada que descreve as etapas necessárias para criação de sua própria estrutura de compensação customizada:

Lista 2. Exemplo de estrutura de compensação customizada
public class CompController {

   //contains activities and the callback method to reverse the activity
   private Map compensationMap;

   //contains a list of active compensation scopes and activity sequence numbers
   private Map compensationScope;

   public CompController() {
      //load compensation map containing callback classes and methods
   }

   public void startScope(String compId) {
      //send jms start message containing compId as JMSXGroupId
   }

   public void registerAction(String compId, String action, Object data) {
      //send jms data message containing sequence number and data
      //using compId as JMSXGroupID.
      //CompController manages sequence number internally using the
      //compensationScope buffer and stores in JMSXGroupSeq message field
   }

   public void stopScope(String compId) {
      //consume and remove all messages having compId as the JMSXGroupID
      //without taking action
      //remove compId entries from compensationScope buffer
   }

   public void compensate(String compId) {
      //consume all messages having compId as the JMSXGroupID and process in
      //reverse order
      //using the compensation map and reflection to invoke reversal methods
      //remove compId entries from compensationScope buffer
   }
}

A visualização compensationMap contém uma lista pré-carregada de todas as atividades (pelo nome) e a classe e o método (pelo nome) correspondente da atividade de reversão. O conteúdo deste exemplo pode conter as seguintes entradas: {"insertTrade", "TradeDAO.insertTradeComp"} e na {"updateAcct", "AcctDAO.updateAcctComp"}. A visualização compensationScope contém uma lista de escopos de compensação ativos pelo compId e as atividades que foram registradas até então. Este buffer é usado para obter o próximo número de sequência usado pelo método registerAction() . O restando dos métodos são razoavelmente autoexplanatório.

Observe que estou usando o sistema de mensagens Java Message Service (JMS) para a implementação do coordenador de compensação. Escolhi esta técnica principalmente porque ela fornece uma forma de garantir (apesar do uso de mensagens persistentes e entrega garantida) que na ocorrência de uma falha durante a compensação, as transações que não puderam ser revertidas ainda estejam na fila JMS e podem ser selecionadas e executadas por um outro encadeamento. O sistema de mensagens JMS também permite a possibilidade de um processamento de registro e compensação de atividade assíncrona, além de acelerar o código de origem do aplicativo. Claro, manter a informação de compensação na memória aceleraria significativamente o processamento, mas poderia resultar em mais inconsistências do banco de dados se o coordenador de compensação falhasse.

O exemplo de código de origem na Lista 3 ilustra a técnica de aplicação de uma estrutura de compensação customizada para o código de origem do aplicativo original na A Lista 1:

Lista 3. Exemplo de negociação de ações com estrutura de compensação
public class TradingService {

   private CompController compController = new CompController();
   private AcctDAO acctDao = new AcctDAO();
   private TradeDAO tradeDao = new TradeDAO();

   public void processTrade(TradeData trade) throws Exception {

      String compId = UUID.randomUUID().toString();
      try {
         //start the compensation scope
         compController.startScope(compId);

         //get the original account values and set the acct balance
         AcctData acct = acctDao.getAcct(trade.getAcctId());
         double oldBalance = acct.getBalance();
         if (trade.getSide().equals("BUY")) {
            acct.setBalance(acct.getBalance()
               - (trade.getShares() * trade.getPrice()));
         } else {
            acct.setBalance(acct.getBalance()
               + (trade.getShares() * trade.getPrice()));
         }

         //insert the trade and update the account
         long tradeId = tradeDao.insertTrade(trade);
         compController.registerAction(compId, "insertTrade", tradeId);

         acctDao.updateAcct(acct);
         compController.registerAction(compId, "updateAcct", oldBalance);

         //close the compensation scope
         compController.stopScope(compId);

      } catch (Exception up) {
         //reverse the individual database operations
         compController.compensate(compId);
         throw up;
      }
   }
}

Ao revisar a Lista 3, observe que ao definir a unidade de trabalho transacional, primeiro você inicia o escopo de compensação usando o método startScope() . Em seguida, você deve salvar o saldo original para que você o passe para o coordenador ao registrar a atividade. Assim que uma atividade for concluída, você registrará essa atividade usando o método registerAction() . Isso diz ao coordenador de compensação que uma operação de atualização do banco de dados foi concluída com êxito e precisa ser incluída na lista de possíveis atividades de compensação. Se a LUW inteira for concluída com êxito, então você invocará o método stopScope() , que remove todas as referências do coordenador de compensação. Entretanto, se ocorrer uma exceção, você invocará o método compensate() , que administra a reversão, independentemente das atividades que foram consolidadas no banco de dados.

O código de origem nas Listas 2 e na 3 estão, certamente, longe de um estado pronto para produção, mas ilustram as técnicas envolvidas na construção de uma estrutura de compensação customizada. Sua estrutura de compensação customizada poderia usar anotações customizadas, aspectos (ou interceptores), ou até mesmo sua própria linguagem específica do domínio (DSL; consulte Recursos) de compensação customizada para tornar o código ainda mais intuitivo. Além disso, não é necessário usar o sistema de mensagens assíncrono JMS para a estrutura de compensação, mas o acho útil para o tratamento de questões que envolvem falhas de compensação.

Conclusão

Optar ou não pelo uso da estratégia de Alto Desempenho, resultará em vantagens e desvantagens. Muitos riscos estão associados a esta estratégia de transação, e ela é complexa de implementar. Entretanto, se desempenho for sua prioridade número um, e seu aplicativo já estiver razoavelmente robusto e livre de erros, então esta é uma estratégia adequada para garantir pelo menos algum nível de integridade e consistência do banco de dados sem afetar de forma prejudicial o desempenho. Recomendaria este tipo de solução se o desempenho não fosse sua principal preocupação? Certamente não. Você sempre deve tentar usar as propriedades ACID tradicionais em seu aplicativo. Entretanto, se você estiver propenso a abrir mão de algum nível de consistência do banco de dados e integridade de dados em troca do desempenho, então você deverá considerar a estratégia de Alto Desempenho.

Nesta parte de série, mostrei algumas das armadilhas e desafios associados ao processamento de transações e apresentei quatro estratégias de transação que você pode usar para construir uma solução de transação robusta para seu aplicativo. O processamento de transações pode parecer simples visto de fora, mas quando você começa a aplicá-lo em vários cenários de aplicativos de negócios, ele pode ficar bastante complexo. Meu objetivo nesta série foi reduzir essa complexidade e mostrar técnicas e estratégias para simplificar o que é visto como uma tarefa desafiadora — manter um alto grau de integridade e consistência de dados. Espero que esses artigos sobre transações tenham fornecido o conhecimento necessário para melhorar a robustez de seus aplicativos e dados a partir do ponto de vista do processamento de transações.


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=422883
ArticleTitle=Estratégias de Transação: A Estratégia de Alto Desempenho
publish-date=07222009