PLATAFORMA PINHÃO PARANÁ Solução para Gerenciamento de Transações no Framework Pinhão Abril – 2006 Sumário de Informações do Documento Tipo do Documento: Definição Título do Documento: SoluçãoCELEPARpara gerenciamentode Transaçõesno HIBERNATE Estado do Documento: Elaborado Responsáveis: José AugustoSoaresPrado Palavras-Chaves: Hibernate, transações, Plataforma Pinhão Resumo: Transaçãoé um conceito fundamentalde todo sistemade bancode dados Número de páginas: 09 Software utilizados: Versão Data Mudanças 1.0 04/2006 Elaboração SUMÁRIO INTRODUÇÃO.......................................................................................................................................................4 TRANSAÇÕES ANINHADAS...............................................................................................................................4 PROBLEMAS ENCONTRADOS..........................................................................................................................5 MÉTODOS IMPORTANTES ............................................................................................................................................6 POSSÍVEIS COMPLICAÇÕES JÁ TRATADAS......................................................................................................................7 EXEMPLOS DE UTILIZAÇÃO...........................................................................................................................8 4 INTRODUÇÃO Transação é um conceito fundamental de todo sistema de banco de dados. O ponto essencial de uma transação é que vários passos são unidos em um único processo atômico. Defini-se processo atômico ou bloco de código atomizado como um bloco de código repleto de procedimentos onde é exigida a condição: ou todos os procedimentos são concluídos com sucesso ou nenhum deve ser realizado de fato. A Plataforma Pinhão utiliza o framework HIBERNATE para persistência de objetos e este usa a linguagem HQL como interface SQL ao desenvolvedor, isto faz com que se programe sempre a mesma consulta HQL independentemente de qual banco de dados é utilizado. Além disso, o HIBERNATE trata de maneira transparente as chaves primárias, estrangeiras e tabelas associativas, abstraindo o acesso aos dados e facilitando uma possível mudança de fornecedor de banco de dados. Os patterns DAO e FAÇADE, utilizados pela Plataforma Pinhão Paraná, foram criados com o intuito de modularizar de maneira organizada as camadas e tarefas dentro do modelo MVC (Model View Controller) em um sistema. Ambos patterns “trabalham” em conjunto na camada Model, cada qual com suas atribuições. Tendo estes conceitos em mente, trataremos dos pontos relevantes em transações e da solução adotada pela Plataforma Pinhão para melhorar o controle de transações na sua arquitetura. TRANSAÇÕES ANINHADAS Transações aninhadas são transações dentro de transações, ou seja, dentro de um bloco de SQL atomizado encontra-se outro sub-bloco de código SQL que deve ser atomizado também, independentemente do bloco pai. Esse recurso é provido por alguns bancos de dados porém não é suportado pelo HIBERNATE. PINHÃO- FRAMEWORK- CELEPAR 5 Por exemplo: BEGIN; UPDATE .... (1) BEGIN; UPDATE .... (2) COMMIT; UPDATE .... (3) ROLLBACK; Caso o código acima venha a ser passado para um banco de dados sem suporte a transações aninhadas, a interpretação será um tanto confusa e errada. Este banco de dados ignorará o segundo BEGIN, pois já existe uma transação aberta. Porém realizará o COMMIT considerando o primeiro BEGIN. Ao encontrar o comando ROLLBACK, a ação é desfazer tudo até o ultimo COMMIT, então será desfeito apenas o UPDATE ... (3). Essas limitações impossibilitam o uso de transações aninhadas no momento. PROBLEMAS ENCONTRADOS Ao utilizar como padrão a abertura de transações nas classes do tipo DAO alguns problemas de padronização eram encontrados. Pelo fato de nem toda transação se resumir a um único método da classe DAO, a conexão com o banco, ou sessão no caso do HIBERNATE, precisa ser passada de alguma forma para o próximo método que irá continuar a execução da transação. Apesar da solução para esse problema ser simples, isso faz com que cada desenvolvedor resolva de uma forma diferente, o que ocasiona falta de padronização na codificação, dificultando a manutenção do código e principalmente incompatibilidades com a especificação do sistema. Outro problema levantado acontecia quando uma Façade precisava chamar o método de outra Façade, onde ambos precisam controlar transações. Neste caso transações aninhadas seriam abertas, o que já vimos que não é suportado. PINHÃO- FRAMEWORK- CELEPAR 6 SOLUÇÃO A solução adotada foi a de não abrir uma sessão (conexão) para cada query que desejamos fazer, e sim fazer com que uma mesma sessão seja usada para um mesmo request, isto é, uma mesma Thread. Para tornar isso possível e conciliável com os padrões DAO e FAÇADE a solução é abrir a transação nas classes do tipo FAÇADE e utilizar os novos métodos do Framework Pinhão para controle de transações e sessões. Como foi dito anteriormente quando uma Façade precisar chamar o método de outra Façade poderíamos ter um problema pois transações aninhadas seriam abertas devido ao fato de estar especificado que cada Façade deve ter a sua transação. Para evitar que sejam realmente abertas transações aninhadas, o Framework Pinhão se encarregará de ignorar essa nova abertura de transação. Métodos Importantes Tal controle de transações não precisará ser preocupação do desenvolvedor desde que este use a chamada das transações e sessões através dos métodos estáticos currentSession e/ou currentTransaction da classe HibernateUtil do Framework Pinhão. O método currentTransaction deve ser chamado nas classes do tipo FAÇADE, quando necessitarem de controlar transações, enquanto o método currentSession deve ser chamado em todas as classes do tipo DAO. Estes métodos abrem transação e sessão, respectivamente, e os associam a Thread da requisição. Para fechar a transação e sessão o desenvolvedor deve utilizar os métodos HibernateUtil.commitTransaction ou o HibernateUtil.rollbackTransaction. Todas as classes DAO deve chamar o método HibernateUtil.closeSession, este método só fechará realmente a sessão (conexão) se não estiver dentro de uma transação. Seguindo a mesma lógica de abertura, a transação deve ser fechada na FAÇADE e a sessão “fechada” na DAO. Isso pode parecer um pouco estranho a primeira vista, mas o fato é que utilizando esses métodos, a sessão não será de fato fechada caso ainda exista uma PINHÃO- FRAMEWORK- CELEPAR 7 transação aberta. Porém é importante a utilização desde padrão pois facilitará a manutenção e garantirá um melhor reaproveitamento de código. Para entender melhor o uso destes métodos tão importantes verifique os exemplos disponíveis neste documento. A Plataforma Pinhão fará um controle transacional e ignorará as transações aninhadas que virão a ser chamadas nesses casos, passando para o HIBERNATE apenas a transação principal, ou seja, a primeira que foi aberta e o último fechamento (seja COMMIT ou ROLLBACK). Possíveis Complicações já Tratadas Existem então, quatro maneiras diferentes de uma transação aninha ser formada: BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN COMMIT ROLLBACK COMMIT ROLLBACK COMMIT COMMIT ROLLBACK ROLLBACK Dentre essas quatro maneiras, apenas a segunda maneira apresenta um problema em potencial. Caso aconteça um ROLLBACK na transação interna, o componente HibernateUtil do Framework Pinhão guardará essa informação e fará um ROLLBACK na transação principal, mesmo que ao final seja chamado um COMMIT. É importante fazer um bom controle de exceções no caso de um ROLLBACK ser acionado dentro de uma transação interna. Uma boa prática neste caso é que o desenvolvedor sempre lance uma exceção logo após o ROLLBACK, pois caso essa situação ocorra a FAÇADE, externa que gerou a primeira transação, poderá capturar essa exceção e fazer o devido tratamento. PINHÃO- FRAMEWORK- CELEPAR 8 EXEMPLOS DE UTILIZAÇÃO Seguem abaixo, exemplos de métodos de FAÇADE e de DAO utilizando o componente HibernateUtil do Framework Pinhão para controlar transação e sessão. Exemplo de método da FAÇADE, iniciando a transação e chamando um método da classe DAO para salvar um aluno. public String salvarAluno(Aluno aluno) throws ApplicationException, Exception { String retornoNatural = null; DAOFactory hibernateFactory = DAOFactory.getDAOFactory(DAOFactory.HIBERNATE); try { HibernateUtil.currentTransaction(); //Abre sessão e transação AlunoDAO alunoDao = hibernateFactory.getAlunoDAO(); alunoDao.salvarAluno(aluno); retornoNatural = alunoDao.consultaNatural(); HibernateUtil.commitTransaction(); //Fecha sessão e transação } catch (ApplicationException appEx) { HibernateUtil.rollbackTransaction(); throw appEx; } catch (Exception ex) { HibernateUtil.rollbackTransaction(); throw new ApplicationException("mensagem.erro.matricula.servico.salvarAluno", ex, ApplicationException.ICON_ERRO); } return retornoNatural; } Exemplo de método de busca em uma DAO, tenha em mente que é de essencial importância o tratamento das exceção: public Aluno buscarAlunoPorPK(Integer codAluno) throws ApplicationException, Exception { Aluno aluno = null; try { Session session = HibernateUtil.currentSession(); aluno = (Aluno) session.load(Aluno.class, codAluno); logAuditoria.info("BUSCA DE ALUNO: Aluno "+ aluno.getNomeAluno() +" consultado por Xxxxxx"); PINHÃO- FRAMEWORK- CELEPAR 9 } catch (HibernateException he) { throw new ApplicationException("mensagem.erro.matricula.listaDeAlunos", he); } catch (Exception e) { throw e; } finally { HibernateUtil.closeSession(); } return aluno; } CONCLUSÃO Apesar de possíveis limitações da arquitetura, a Plataforma Pinhão está desenvolvendo tecnologia para tornar o desenvolvimento de software mais organizado e robusto, conseqüentemente agilizando o processo de desenvolvimento. A utilização dos novos métodos da classe HibernateUtil facilitará o gerenciamento das transações HIBERNATE e manterá a modularidade proposta com relação a camada de banco de dados. PINHÃO- FRAMEWORK- CELEPAR