Depois de um longo período sem postar (para variar) volto com uma dica que me foi muito útil: configurar o JPA com múltiplas unidades de persistência, ou seja, utilizar mais de um banco de dados em um projeto java.

Recentemente voltei a desenvolver (de verdade) em Java e estou encarando desafios inéditos até então para mim. Estou vendo muitas coisas novas e espero tornar o blog um pouco mais ativo com essas “descobertas”. Talvez 1 ou 2 posts por semestre… =]

Anyway, a motivação desse post é que precisei utilizar dois bancos de dados, um MySQL para leituras e outro PgSQL para escrita. Procurei bastante e achei bastante material, mas nada completo envolvendo configurações dos data sources, das unidades de persistências e das transações num lugar só. Por isso venho tentar unificar isso e ajudar quem precise.

Ah, não irei demonstrar uma aplicação completa, como geralmente faria… Se precisarem de um projeto com as configurações básicas procurem pelo arquétipo do Maven “spring-mvn-jpa-archtype/”.

Bem, para inicio de conversa, nesse meu projeto compatível com Java 6, utilizei Spring 3.0.5, Hibernate 3.6.0 e a implementação do JPA 2.0 pelo Hibernate. Utilizarei annotations, mas não quero exagerar e abolir os XMLs ^^ .

Primeiramente a configuração dos bancos:

database.xml

Observe que criei uma série de recursos para cada banco, isolando assim as conexões a eles.

Nesse caso, referenciei 2 locais diferentes para as configurações do Persistence Unit. Por padrão, o arquivo “META-INF/persistence.xml” é carregado. Mas, como quero poder referenciar diferentes Unidades de Persistência por nome, criei dois arquivos diferentes com praticamente o mesmo conteúdo.

META-INF/my_persistence.xml

META-INF/pg_persistence.xml

A única diferença é o nome da Unidade de Persistência. Para o mesmo efeito pode-se manter as definições acima no mesmo arquivo (por exemplo no padrão “META-INF/persistence.xml”) e setar o nome das unidades nos beans LocalContainerEntityManagerFactoryBean.

Sobre o placeHolderDefault (PropertyPlaceholderConfigurer), serve para injetar valores de propriedades que utilizo depois (como ${my.driver}) obtidos de um simples arquivo de texto.

db.properties

Agora, para podermos utilizar as anotações @Transactional e @PersistenceUnit, temos que incluir:

Observação: é comum a inclusão do PersistenceAnnotationBeanPostProcessor, mas isso é feito automaticamente quando usa-se context:component-scan ou context:annotation-config.

Agora basta definir os EntityManagers para permitir as operações em ambos os bancos e as Transactions para persistir corretamente.

No meu caso, utilizei uma classe abstrata BaseManager com algumas operações básicas. Nas classes filhas especifiquei as unidades de persistência.

BaseManager.java

Observe que o getEntityManager(), essencial para as operações, é abstrato.

UserManager.java

Assim, para a classe UserManager o banco usado será o PostgreSQL.

Note que as operações que precisam de uma transação foram sobrescritas para permitir a utilização de um @Transactional específico.

Done! Com isso feito, basta testar!

E por hoje é só pessoal.