Você está na página 1de 15

Controle de Transao com Spring, JTA, JPA, Hibernate e Maven Marcadores: Hibernate, JPA, JTA, Maven, Spring, Transaction,

Transao Com o crescimento das aplicaes que vm sendo desenvolvidas um dos maiores problemas na estruturao de um projeto reside no controle de transaes. Quando vrios datasources entram na histria o problema s aumenta. Segue abaixo uma proposta de soluo para o controle de transao utilizando String, com JTA e Maven. As configuraes abaixo necessitam de um container J2EE para funcionarem, o exemplo foi testado no JBoss 4.0.5ga. Com o uso do Spring o controle transacional se torna transparente, sendo ento o problema resolvido. Segue tutorial abaixo: Configuraes do Maven A configurao do Maven para o uso de tais ferramentas simples.

Somente so necessrias algumas dependncias e um repositrio para busca-las.

Adicionando dependncias O seguinte trexo deve ser adicionado nas dependncias do projeto no seu arquivo pom.xml.

view plaincopy to clipboardprint? <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>2.5.4</version>

</dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.3.1.ga</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> <scope>provided</scope>

</dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.2.6.ga</version> <exclusions> <exclusion> <groupId>javax.transaction</groupId> <!-- Exclusion to remove a classloader conflit with jta of JBoss --> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.1.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.3.0.ga</version>

</dependency> Aqui esto listados todos os jars necessrios para o uso das ferramentas mencionadas neste tutorial.

Adicionando repositrio O seguinte trexo deve ser adicionado nos repositrios do projeto para que todas as dependncias sejam satisfeitas.

Tal repositrio contm algumas das dependncias do Hibernate.

view plaincopy to clipboardprint? <repository> <id>maven-repository.dev.java.net</id> <name>Java Dev Net Repository</name> <url>http://download.java.net/maven/2/</url> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> Utilizao do Spring Com a utilizao do Spring podemos injetar o EntityManager do JPA no Dao, utilizando como provider o Hibernate.

O controle de transao se torna transparente para o desenvolvedor no sendo mais necessrio que o mesmo inicie e finalize cada transao.

Vejamos utilizar o Spring no escopo proposto.

Configurao do applicationContext Abaixo segue uma configurao padro para o applicationContext da aplicao

view plaincopy to clipboardprint? <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jboss="http://www.springmodules.org/schema/jboss" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" default-autowire="byName"> <bean id="dao" scope="prototype" class="br.com.product.project.commons.dao.DaoImpl"> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBea n"> <property name="jpaProperties">

<props> <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATran sactionFactory </prop> <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transactio n.JBossTransactionManagerLookup </prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" > <property name="transactionManagerName" value="java:/TransactionManager" /> <property name="userTransactionName" value="UserTransaction" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" />

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPost Processor" /> </beans> No xml acima temos vrias configuraes, vamos detalhar uma por uma.

Injeo do Dao na Aplicao No XML acima temos a declarao de um Bean chamado dao. Esse bean implementa o Dao que ser utilizado na nossa aplicao.

Para utiliza-lo devemos fazer com que o Spring injete o mesmo na camada de Aplicao.

Como essa injeo deve ser feita foge o escopo desse tutorial.

Configurao do EntityManager do JPA Vemos tambm no applicationContext configurao do EntityManagerFactory do JPA.

No property jpaVendorAdapter definimos o uso do Hibernate como provider do JPA.

Definimos tambm algumas propriedades do Hibernate.

Para que o EntityManager seja inicializado no Dao o seguinte fragmento de cdigo deve existir no mesmo:

view plaincopy to clipboardprint? private EntityManager entityManager; @PersistenceContext( type=PersistenceContextType.TRANSACTION, name="name" ) public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } Neste fragmento dizemos ao Spring que a varivel entityManager vai receber uma instncia criada pelo EntityManagerFactory.

Assim o Spring injeta o EntityManager no Dao.

Controle Transacional No fim do applicationContext vemos a configurao do Controle de Transao.

Definimos o JpaTransactionManager como o controlador de transaes, e logo abaixo definimos que o mesmo seja feito atravs de annotations.

Logo para definirmos quando um mtodo deve ser executado em uma transao tudo que precisamos fazer adicionar um annotation em cima do mesmo:

view plaincopy to clipboardprint? @Transactional(propagation = Propagation.REQUIRED, readOnly = false) public void someMethod(){ // do some operation in a transaction } O mesmo annotation pode ser adicionado em uma classe ou em uma interface, agindo assim sobre todos os metodos das mesmas.

Programando o DAO Uma vez que possumos o EntityManager injetado no Dao e o controle de transao j est definido a programao do Dao se torna muito simples.

Vejamos um exemplo de um mtodo que insere ou atualiza uma Entidade.

view plaincopy to clipboardprint? public void save(T t) throws DataBaseException { try{

//Consideremos que todas as entidades passadas para esse metodo possuam o metodo getId Object id = t.getId(); if( id != null ){ entityManager.merge( t ); else{ entityManager.persist(t); entityManager.flush(); } catch (Exception e) { throw new DataBaseException( "Erro ao persistir objeto <" + t.getClass().getSimpleName() + ">", e ); } } Mapeamento no Hibernate com Annotations O mapeamento das entidades pode ser feito todo via annotation reduzindo o nmero de XML's para a configurao da aplicao.

O nico XML necessrio o persistence.xml, padro do JPA que explicita as caractersticas na Unidade de Persistencia.

Configurao do persistence.xml Um exemplo de configurao do persistence.xml pode ser visto a seguir

view plaincopy to clipboardprint? <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"

version="1.0"> <persistence-unit name="name" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/MySqlAccounter</jta-data-source> <class>br.com.product.project.domain.vo.Home</class> <class>br.com.product.project.domain.vo.Room</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> <property name="hibernate.cache.use_second_level_cache" value="false" /> <property name="hibernate.cache.use_query_cache" value="false" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.generate_ddl" value="true" /> </properties> </persistence-unit> </persistence> No arquivo configuramos a Unidade de persistencia que ser usada pelo JPA.

Perceba que definimos um nome para a mesma, esse nome o mesmo que deve ser adicionado sobre o entity manager no annotation que o injeta no Dao, mostrado no item Configurao do EntityManager do JPA.

A primeira configurao mostra que o provider do JPA ser o hibernate.

Logo em seguida configurado o endereo do DataSource da base de dados que a Unidade de Persistncia ir utilizar.

Em seguida so listadas todas as classes que queremos mapear para que o JPA possa encontrlas e iniciar o mapeamento das mesmas.

No exemplo o dialeto MySQLDialect usado pois o mesmo se conectar a uma base de dados MySQL, tal varivel deve ser alterada de acordo com o SGBD utilizado, tambm desabilitamos o segundo nvel de cache e a cache de queries.

Annotations de Mapeamento Uma vez que definimos quais classes queremos mapear, agora precisamos inserir metadados nas mesmas para que o mapeamento seja feito corretamente.

Para isso utilizamos os annotations da javax.persistence.*.

Se tivermos a seguinte tabela em nossa base de dados:

view plaincopy to clipboardprint? CREATE TABLE TAB_HOME ( id INT AUTO_INCREMENT PRIMARY KEY, address VARCHAR(50) ); Vejamos um exemplo de mapeamento para a mesma

view plaincopy to clipboardprint? package br.com.product.project.domain.vo;

import javax.persistence.Column; import javax.persistence.Entity;

import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.GeneratedValue;

@Entity @Table(name = "TAB_HOME" ) public class DomainEnumSubscriber {

@Id @GeneratedValue @Column( name="id" ) private Integer id;

@Column( name="address" ) private String address;

public Integer getId(){ return this.id; }

public void setId( Integer id ){ this.id = id }

public String getAddress(){ return this.address; }

public void setAddress( String address ){ this.address = address; } } No cdigo usamos o annotation @Entity para mostrarmos que a classe representa uma entidade.

Em seguida usamos o anntation @Table para mostrar qual tabela estamos mapeando.

O annotation @Id mostra que o atributo se referencia a uma chave primria. e o anntation @GeneratedValue que a mesma gerada automaticamente pelo banco de dados.

Em seguida o annotation @Collumn serve para mapear qual a coluna que o atributo se referencia.

Existem vrias anotaes cada uma com seus atributos, veja mais na Documentao Oficial.

Mapeamento de Chaves Estrangeiras Com o JPA podemos mapear as chaves estrangeiras das tabelas para que objetos j sejam inseridos dentro das entidades que as contm. Suponhamos as seguintes tabelas no banco de dados

view plaincopy to clipboardprint? CREATE TABLE TAB_HOME ( id INT AUTO_INCREMENT PRIMARY KEY,

address VARCHAR(50) );

CREATE TABLE TAB_ROOM ( id INT AUTO_INCREMENT PRIMARY KEY, home INT REFERENCES TAB_HOME( id ), size INT, ); Podemos mapear essa chave estrangeira de duas maneiras. Fazendo o Objeto Home ter uma lista de todos os comodos que possui (mapeamento do tipo OneToMany), ou fazendo cada comodo possuir a qual casa ele pertence (Mapeamento do tipo ManyToOne).

Mapeamento OneToMany

Para que possamos ter uma lista em uma entidade pai de todas as entidades filhas que a referenciam utilizamos o mapeamento OneToMany.

Para tanto s precisamos utilizar o annotation @OneToMany ao fazer o mapeamento de um atributo de uma das classes mapeadas.

Vejamos um exemplo:

view plaincopy to clipboardprint? //O atributo mappedby se referencia a uma instancia de Home dentro da classe Room com o nome home @OneToMany( targetEntity=Room.class, mappedby="home" ) private Collection rooms; Com isso ao criar o objeto o mesmo busca uma lista de todos os comodos

que referenciam a ele de modo lazy.

Mapeamento ManyToOne

Para que possamos ter uma instncia de um objeto ao qual uma chave estrangeira aponta utilizamos o mapeamento ManyToOne.

Para tanto s precisamos utilizar os annotations @ManyToOne e @JoinColumn ao fazer o mapeamento de um atributo de uma das classes mapeadas.

Vejamos um exemplo:

view plaincopy to clipboardprint? @ManyToOne( targetEntity=Home.class ) @JoinColumn( name="home" ) private Home home; Com isso ao criar o objeto o mesmo busca o objeto ao qual a chave estrangeira se relaciona e o traz de modo lazy.

Mais pode ser encontrado em sites como o de referencia do Spring ou nesse tutorial sobre J2EE.

Por favor, se voc leu esse material deixa sua crtica, comentrio e sujestes de melhoras

[]'s e at a proxima

Você também pode gostar