• Nenhum resultado encontrado

4.1.

Transações de bancos de dados

Uma aplicação empresarial típica acessa e armazena informações em um ou mais bancos de dados. Como essas informações são críticas para operações de negócios, elas devem ser precisas, atuais e confiáveis. A integridade dos dados seria perdida se múltiplos programas tivessem permissão para atualizar simultaneamente as mesmas informações. A integridade dos dados também estaria comprometida se um sistema que falhasse durante o processamento de uma transação comercial fosse deixar os dados afetados apenas parcialmente atualizados. Para evitar esses dois cenários, as transações de software garantem a integridade dos dados. As transações controlam o acesso concorrente aos dados por múltiplos programas. No caso de uma falha no sistema, as transações se certificam de que, após a recuperação, os dados estarão em um estado consistente (BODOFF et. al, 2002).

Segundo (DATE, 1988), a transação é uma unidade de trabalho. A finalidade fundamental do sistema de banco de dados é realizar transações. Ela consiste na execução de uma seqüência de operações especificadas pela aplicação, começando com uma operação especial BEGIN TRANSACTION, e terminando ou com uma operação COMMIT ou com uma operação ROLLBACK. COMMIT é utilizado para sinalizar o término bem-sucedido (a unidade de trabalho foi completada com sucesso); ROLLBACK é usado para sinalizar o término mal-sucedido (a unidade de trabalho não pôde ser completada com sucesso por haver ocorrido alguma siuação excepcional).

Na figura 13 é possível observar as situações possíveis de uma transação. A primeira obteve êxito e foi finalizada corretamente com um COMMIT, já no segundo caso houve um problema e a transação foi finalizada com um ROLLBACK. Quando houver uma falha, a transação será desfeita e desfará as alterações já feitas na transação.

Figura 13 Transações e execução de programa (DATE, 1988) 1ª Transação 2ª Transação BEGIN TRANSACTION COMMIT BEGIN TRANSACTION Inicio Programa Fim Program a ROLLBACK

As transações não podem ser aninhadas, isto é, BEGIN TRANSACTION só pode ser executado quando a aplicação não possuir, correntemente nenhuma transação em andamento. Inversamente, COMMIT e ROLLBACK só podem ser executados quando

uma transação estiver em andamento. Uma transação possui quatro propriedades

críticas (AKBAR-HUSAIN e LANE, 2001):

Atomicidade: ou todas as ações da transação acontecem, ou nenhuma.

Consistência: se a transação é consistente e o banco de dados começa consistente, ele termina consistente.

Isolação: a execução de uma transação é isolada da execução de outras transações. Durabilidade: se uma transação é concluída com sucesso (através de uma operação COMMIT bem sucedida), então seus efeitos são persistentes (duráveis). Devido à atomicidade de uma transação, quando um objeto de granulação grossa, como o Composite Entity (ALUR e CRUPI e MALKS, 2002), for alterado, todo o processo deverá ser feito em uma única transação, pois se um objeto dependente for alterado, e houver falha na alteração de outro objeto, a alteração do primeiro também deverá ser desfeita.

4.2.

Transações em EJBs

Existem dois tipos de transações para EJBs: gerenciada por bean e gerenciada por contêiner (BODOFF et. al, 2002).

4.2.1

Transações gerenciadas por bean

Em transações gerenciadas por bean, as delimitações da transação são explícitas do código de um bean de sessão ou de um bean orientado à mensagem. Beans de entidade não podem ter suas transações gerenciadas por bean; elas devem ser gerenciadas pelo contêiner. Ao codificar uma transação gerenciada por bean para beans de sessão ou orientados a mensagem, pode-se usar transações JDBC ou JTA (Java Transaction API) (BODOFF et. al, 2002).

Uma transação JDBC é controlada pelo gerenciador de transações do SGBD (Sistema de Gerenciamento de Banco de Dados). A codificação de uma transação JDBC

é feita através da invocação dos métodos commit e rollback da interface

java.sql.Connection. O início da transação é implícito. Ela começa com a primeira instrução SQL que segue a instrução commit, rollback ou connect

mais recente.

As transações JTA podem ser demarcadas de forma independente do gerenciador de transação. O controle de uma transação JTA é feita pelo gerenciador de transações

J2EE. Uma transação JTA é demarcada pelos métodos begin, commit e rollback

da interface javax.transaction.UserTransaction. As chamadas begin e

commit delimitam as atualizações para o banco de dados. Se as atualizações falharem, o código invoca o método rollback para desfazer as ações da transação e lança uma exceção.

4.2.2

Transações gerenciadas por contêiner

Todos os tipos de enterprise beans podem ter suas transações gerenciadas por contêiner. O contêiner define as delimitações da transação. Isto simplifica a codificação, pois não é necessário incluir comandos no código que iniciem e terminem a transação (BODOFF et. al, 2002).

As transações gerenciadas por contêiner não exigem que todos os métodos estejam associados a transações. Ao implantar um bean, é possível especificar qual dos métodos do bean estará associado às transações configurando os atributos de transação.

O atributo de transação controla o escopo de uma transação. Há seis tipos de transações gerenciadas por contêiner:

Required RequiredNew Mandatory NotSupported Supports Never

Com base nesses atributos o contêiner pode criar ou não uma transação para a invocação de um método de um bean, não fazer nada ou mesmo disparar uma exceção.

Uma descrição completa destes atributos pode ser encontrada em (ROMAN e AMBLER e JEWELL, 2002). Para o propósito deste trabalho apenas o atributo Required será explicado. Os métodos de um bean marcados como Required devem ser invocados dentro do escopo de uma transação. Se a transação já existe (isto é, o método é chamado de um cliente como parte de uma transação existente), o método Required do bean é incluído no escopo da transação corrente. Se não for chamado no contexto de uma transação, então um novo escopo de transação é criado e o método é adicionado a esta nova transação (AKBAR-HUSAIN e LANE, 2001).

Em função da simplicidade, transações gerenciadas por contêiner permitem que o programador foque mais sua atenção na lógica de negócio, abstraindo os comandos de delimitações das transações. Conseqüentemente também é o mais viável para o contexto deste trabalho. O foco principal é detectar objetos desatualizados.

4.2.3

Problema de atualização com transações

Quando uma aplicação roda em um ambiente multiusuário, cedo ou tarde dois usuários tentarão atualizar o mesmo registro. Se não houver um mecanismo para tratar esta situação, é possível que, em algum momento que o cliente esteja alterando um registro, o registro esteja desatualizado. Pois outro usuário pode tê-lo alterado antes. Para evitar este problema existem algumas técnicas que permitem contornar este problema. Abordaremos aqui duas estratégias para fazer a atualização dos dados: com bloqueio pessimista e bloqueio otimista (MACORATTI, 2002).

No bloqueio pessimista, quando o cliente lê um registro para fazer uma atualização, este registro é bloqueado impedindo que outros clientes tenham acesso a ele. Ele permanecerá bloqueado, ou seja, nenhum outro cliente terá acesso a ele, mesmo para leitura, até que o método de atualização seja executado e os dados sejam armazenados na base. A desvantagem é que o registro poderá permanecer um longo período bloqueado. Com bloqueio otimista, o bloqueio do registro é feito somente quando o método de atualização for executado. O bloqueio é imediatamente liberado quando se completa a operação de atualização. Porém, se dois usuários acessarem um registro para atualização ao mesmo tempo, conseqüentemente, aquele que atualizar por último estará salvando dados desatualizados, pois o primeiro usuário já armazenou suas alterações.

Uma transação longa executa uma série de comandos do banco de dados que podem levar muito tempo horas, dias, semanas, ou ainda meses. Em contraste, uma transação curta executa um grupo de comandos em alguns segundos. Para aplicações que utilizam EJBs, o uso transações curtas é tomado como padrão. Transações longas também são viáveis com EJBs, mas isso pode acarretar em problemas de escalabilidade. Esses problemas poderão ser analisados como maiores detalhes consultando as referências bibliográficas (AKBAR-HUSAIN e LANE, 2001).

Não convém um cliente aguardar um longo período se quiser apenas ler alguns dados. Desta forma, o bloqueio otimista prova maior eficiência para sistemas concorrentes, e será base para esta discussão.

Vale ressaltar aqui que um registro nada mais é que um objeto para EJB, implementado como o padrão Value Object. Em sistemas concorrentes distribuídos esses objetos são compartilhados, o que gera alguns conflitos.

Para detectar os conflitos de atualização, há pelo menos três estratégias para detectar as alterações (AKBAR-HUSAIN e LANE, 2001).:

Timestamp - o objeto deve conter um campo do tipo Timestamp que guarda a data e hora da última alteração. Quando o objeto for atualizado este campo é comparado com a última atualização. Se estiver com um valor diferente significa que o objeto já foi alterado.

Número de versão - é adicionado ao objeto um campo numérico para conter o número da versão do objeto. Quando o objeto for atualizado este campo é comparado com a última atualização. Se estiver com um valor diferente significa que o objeto já foi alterado.

Comparação de estado esta técnica é mais complexa. O objeto é relido e seu estado é comparado com o estado da cópia original. Isto envolve a comparação de vários campos, o que o torna mais caro que as outras técnicas. Se os estados forem iguais, o objeto não será atualizado.

É possível analisar que as primeiras técnicas são mais simples, tanto a primeira como a segunda. A comparação de estado tornaria o projeto mais complexo e caro. Desta forma, a comparação por número de versão será adotada.

Documentos relacionados