Como usar vários bancos de dados com JPA/Hibernate

Olá pessoal! Hoje estou postando duas classes do meu projeto Generic Spatial DAO. Elas exemplificam como lidar com vários persistence unit e mostra o uso da classe ThreadLocal. Explicações no próprio código.


import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.apache.log4j.Logger;

/**
 *
 * @author joaosavio
 *
 */
public class EntityManagerFactoryService {

	private static final Logger LOG = Logger.getLogger(EntityManagerFactoryService.class);
	private static Map<String, EntityManagerFactory> factories = new HashMap<String, EntityManagerFactory>();

	/**
	 * This method returns an entity manager factory for a target persistence unit
         *
	 * @param persistenceUnitName
	 * @return an entity manager factory for a target persistence unit
	 */
	public static EntityManagerFactory getEntityManagerFactory(
			String persistenceUnitName) {
		if (factories.containsKey(persistenceUnitName)) {
			return factories.get(persistenceUnitName);
		}
		EntityManagerFactory emf;
		try {
			emf = Persistence.createEntityManagerFactory(persistenceUnitName);
		} catch (Exception e) {
			// handle exception
		}
		factories.put(persistenceUnitName, emf);
		return emf;
	}

	/**
	 * Close entity manager factories. Use this method when application life cycle ends
	 */
	public static void closeFactories() {
		LOG.info("Closing entity manager factories");
		for (Map.Entry entry : factories.entrySet()) {
			entry.getValue().close();
		}
		factories.clear();
	}
}

 

package org.genericspatialdao.services;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;

import org.apache.log4j.Logger;
import org.genericspatialdao.exceptions.DAOException;

/**
 * 
 * @author Joao Savio C. Longo - joaosavio@gmail.com
 * 
 */
public class EntityManagerService {

	private static final String THERE_IS_NO_ENTITY_MANAGER_IN_SESSION = "There is no entity manager in session";
	private static final String THERE_IS_NO_SESSION = "There is no session";

	private static final Logger LOG = Logger
			.getLogger(EntityManagerService.class);

        // there is a session for each persistence unit
	private static Map<String, ThreadLocal<EntityManager>> sessions = new HashMap<String, ThreadLocal<EntityManager>>();

	/**
	 * Get or create an entity manager
	 * 
	 * @return an entity manager for a target persistence unit
	 */
	public static synchronized EntityManager getEntityManager(
			String persistenceUnitName) {
		ThreadLocal<EntityManager> session = sessions.get(persistenceUnitName);
		if (session == null) {
			session = new ThreadLocal<EntityManager>();
			sessions.put(persistenceUnitName, session);
		}
		EntityManager em = session.get();
		if (em == null) {
			EntityManagerFactory emf = EntityManagerFactoryService
					.getEntityManagerFactory(persistenceUnitName);
			LOG.info("Creating entity manager");
			em = emf.createEntityManager();
			session.set(em);
		}
		return em;
	}

	/**
	 * Get the entity manager for session of a target persistence unit
	 * 
	 * @return the entity manager for session of a target persistence unit
	 */
	public static synchronized EntityManager getEntityManagerForSession(
			String persistenceUnit) {
		LOG.debug("Getting entity manager for session: " + persistenceUnit);
		ThreadLocal<EntityManager> session = sessions.get(persistenceUnit);
		checkSession(session);
		EntityManager entityManager = session.get();
		checkEntityManager(entityManager);
		return entityManager;
	}

	/**
	 * Closes entity manager and remove it from session of a target persistence
	 * unit
	 */
	public static synchronized void close(String persistenceUnit) {
		ThreadLocal<EntityManager> session = sessions.get(persistenceUnit);
		checkSession(session);
		EntityManager entityManager = session.get();
		if (entityManager != null) {
			if (entityManager.isOpen()) {
				LOG.info("Closing entity manager");
				entityManager.close();
			}
			LOG.debug("Removing entity manager from session");
			session.set(null);
		}
	}

	public static void closeAll() {
		LOG.info("Closing all entity managers");
		for (String persistenceUnit : sessions.keySet()) {
			close(persistenceUnit);
		}
	}

	/**
	 * Closes quietly entity manager and session of a target persistence unit
	 */
	public static synchronized void closeQuietly(String persistenceUnit) {
		try {
			close(persistenceUnit);
		} catch (DAOException e) {
			LOG.warn("Exception caught in closeQuietly method: "
					+ e.getMessage());
		}
	}

	/**
	 * Begin a transaction if it is not active
	 */
	public static void beginTransaction(String persistenceUnit) {
		EntityManager em = getEntityManagerForSession(persistenceUnit);
		EntityTransaction transaction = em.getTransaction();
		if (!transaction.isActive()) {
			LOG.debug("Beginning transaction");
			transaction.begin();
		}
	}

	/**
	 * Commit if transaction is active
	 */
	public static void commit(String persistenceUnit) {
		EntityManager em = getEntityManagerForSession(persistenceUnit);
		EntityTransaction transaction = em.getTransaction();
		if (transaction.isActive()) {
			LOG.info("Commiting");
			transaction.commit();
		} else {
			LOG.warn("Commit invoked but transaction is not active");
		}
	}

	/**
	 * Rollback if transaction is active
	 */
	public static void rollback(String persistenceUnit) {
		EntityManager em = getEntityManagerForSession(persistenceUnit);
		EntityTransaction transaction = em.getTransaction();
		if (transaction.isActive()) {
			LOG.info("Rollbacking");
			transaction.rollback();
		} else {
			LOG.warn("Rollback invoked but transaction is not active");
		}
	}

	private static void checkEntityManager(EntityManager entityManager) {
		if (entityManager == null) {
			LOG.error(THERE_IS_NO_ENTITY_MANAGER_IN_SESSION);
			throw new DAOException(THERE_IS_NO_ENTITY_MANAGER_IN_SESSION);
		}
	}

	private static void checkSession(ThreadLocal<EntityManager> session) {
		if (session == null) {
			LOG.error(THERE_IS_NO_SESSION);
			throw new DAOException(THERE_IS_NO_SESSION);
		}
	}
}

Usamos o código acima da seguinte maneira:

EntityManager em = EntityManagerService.getEntityManager(persistenceUnitName);

Simples não?

8 Respostas para “Como usar vários bancos de dados com JPA/Hibernate

  1. Muito bom o post, me ajudou demais! Obrigado!

  2. Olá Joao! ótimo post, é um mérito implementar um componente como este, parabéns! Uma dúvida, eu não entendi bem o uso do método public static synchronized EntityManager getEntityManagerForSession(String persistenceUnit)

    tentei usá-lo da seguinte forma:

    Eu chamo EntityManager getEntityManager(String persistenceUnitName) em um contexto de aplicação, já que vai guardar internamente uma lista de entityManagers, em um contexto de requisição por exemplo, eu uso este método para obter um entityManager, mas ele sempre me retorna null, daí eu uso novamente o EntityManager getEntityManager(String persistenceUnitName) e daí tudo bem, nesse caso, qual a finalidade deste método?

    obrigado meu caro !

  3. Olá,
    getEntityManagerForSession() pré supõe que já existe um entityManager criado. Creio que faltou melhorar a visualização do método (talvez private ou default), não sei, precisaria olhar o projeto.

    Você deve usar o getEntityManager(). No seu caso precisaria ver como está o seu código.

    Abraços

    • Exato João. Eu coloquei este método getEntityManagerForSession() como private, para evitar que alguém cometa o mesmo erro que eu e faça chamadas a ele e estou usando somente getEntityManager(String persistenceUnitName).

      Obrigado pela força.

  4. Olá João vlw pelo post, pois utilizei sua abordagem e funcionou perfeito. Porém não utilizei a opção ThreadLocal, o que isto implicaria, pois até o momento esta funcionando normal.

  5. Achei muito interessante voce chegou a usar com uma aplicação WEB usando algum tipo MVC ?

Deixar mensagem para Moises Cancelar resposta