Manejar dos bases de datos distintas con Hibernate

Alejandro Pérez nos enseña como manejar dos bases de datos distintas con Hibernate

Como manejar dos bases de datos distintas con Hibernate

Índice de contenidos

1. Introducción

2. Entorno

3. Hibernate con más de una base de datos

4. Probando la clase de ayuda

5. Conclusiones

1. Introducción

En ciertas ocasiones nos vemos obligados a manejar en una aplicación más de una base de datos diferente.

En este tutorial vamos a exponer una clase de ayuda para poder gestionar esta situación con Hibernate.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Ahtex Signal X-9500M (Centrino 1.6 GHz, 1024 MB RAM, 60 GB HD).
  • Sistema Operativo: GNU / Linux, Debian Sid (unstable), Kernel 2.6.11, KDE 3.4
  • Máquina Virtual Java: JDK 1.5.0_03 de Sun Microsystems
  • Hibernate 3.0 (http://www.hibernate.org)

3. Hibernate con más de una base de datos

En principio no hay ningún problema para poder gestionar mas de una base de datos con Hibernate.

En Hibernate podemos tener mas de un fichero de configuración, siendo el fichero de configuración por defecto “hibernate.cfg.xml”. Cada fichero de configuración puede representar una conexión a una base de datos distinta, y por supuesto cada fichero de configuración hará referencia a los ficheros de mapeo correspondientes para las tablas de cada base de datos.

La clase que vamos a presentar a continuación pretende facilitar la gestión de está situación, consiguiendo de forma sencilla sesiones de Hibernate a cada una de las bases de datos.

Además la clase se encarga de asegurar que la sesión de Hibernate es única por Thread. Esto puede resultar muy conveniente en aplicaciones multithread o en aplicaciones Web donde múltiples clientes acceden de forma simultánea.

El código de la clase es el siguiente:


Text
package com.autentia.tool;
Text
import java.util.HashMap;
Text
import java.util.Map;
Text
import org.hibernate.HibernateException;
Text
import org.hibernate.Session;
Text
import org.hibernate.SessionFactory;
Text
import org.hibernate.cfg.Configuration;
Text
/**
Text
 * Clase de utilidad para conseguir la sesión de Hibernate.
Text
 * La sesión es única por thread.
Text
 * Pueden existir varios ficheros de configuración.
Text
 * Al menos siempre existirá la configuración por defecto sacada del fichero "hibernate.cfg.xml".
Text
 *
Text
 * @author Autentia
Text
 */
Text
public class HibernateMultipleConfig {
Text
    /** Clave para acceder a la sesión por defecto, esta sesión se obtiene a partir del fichero de configuración "hibernate.cfg.xml". */
Text
    public static final String DEFAULT = "default";
Text
    /** Mapa donde se guardan los SessionFactory para cada uno de los ficheros de configuración. */
Text
    private static final Map<String, SessionFactory> sessionFactorys = new HashMap();
Text
    /** Atributo único por threat donde se guardan las sesiones para cada uno de los ficheros de configuración. */
Text
    private static final ThreadLocal<Map<String, Session>> sessions = new ThreadLocal>();
Text
    static {
Text
        try {
Text
            // Create the DEFAULT SessionFactory from hibernate.cfg.xml
Text
            SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Text
            sessionFactorys.put(DEFAULT, sessionFactory);
Text
        } catch (Throwable e) {
Text
            // Make sure you log the exception, as it might be swallowed
Text
            System.err.println("Initial SessionFactory creation failed." + e);
Text
            throw new ExceptionInInitializerError(e);
Text
        }
Text
        // Creamos el mapa donde se guardará la sesión para cada una de las configuraciones.
Text
        // Este mapa lo guardamos en el atributo sessions, que nos asegura que el mapa es único por thread.
Text
        sessions.set(new HashMap<String, Session>());
Text
    }
Text
    /**
Text
     * Añade un nuevo fichero de configuración, creando el SessionFactory correspondiente.
Text
     * Para encontrar el fichero de configuración, este debe encontrarse en el classpath,
Text
     * junto al fichero de configuración por defecto de hibernate "hibernate.cfg.xml".
Text
     *
Text
     * @param fileName nombre del fichero de configuración que se quiere añadir.
Text
     * @param key clave con la que se hará referencia a esta configuración en las siguientes llamadas.
Text
     * @throws HibernateException si no se puede crear el SessionFactory basado en el fichero que se pasa como
Text
     *             argumento.
Text
     */
Text
    public static void addConfigFile(String fileName, String key) throws HibernateException {
Text
        SessionFactory sessionFactory = new Configuration().configure(fileName).buildSessionFactory();
Text
        sessionFactorys.put(key, sessionFactory);
Text
    }
Text
    /**
Text
     * Devuelve la sesión, para el thread que hace la llamada. Es decir cada thread tiene su propia sesión.
Text
     *
Text
     * @param key clave que identifica la sesión a la que se quiere acceder.
Text
     * @return sesión por defecto, para el thread que hace la llamada.
Text
     * @throws HibernateException
Text
     */
Text
    public static Session currentSession(String key) throws HibernateException {
Text
        Map<String, Session> ss = sessions.get();
Text
        Session s = ss.get(key);
Text
        // Abre una nueva sesión si este thread todavía no tiene ninguna
Text
        if (s == null) {
Text
            s = sessionFactorys.get(key).openSession();
Text
            ss.put(key, s);
Text
        }
Text
        return s;
Text
    }
Text
    /**
Text
     * Cierra la sesión, para el thread que hace la llamada.
Text
     *
Text
     * @param key clave que identifica la sesión que se quiere cerrar.
Text
     * @throws HibernateException
Text
     */
Text
    public static void closeSession(String key) throws HibernateException {
Text
        Map<String, Session> ss = sessions.get();
Text
        Session s = ss.get(key);
Text
        if (s != null) {
Text
            s.close();
Text
            ss.put(key, null);
Text
        }
Text
    }
Text
    /**
Text
     * Devuelve la sesión por defecto, para el thread que hace la llamada.
Text
     * Es decir cada thread tiene su propia sesión.
Text
     *
Text
     * @return sesión por defecto, para el thread que hace la llamada.
Text
     * @throws HibernateException
Text
     */
Text
    public static Session currentSession() throws HibernateException {
Text
        return currentSession(DEFAULT);
Text
    }
Text
    /**
Text
     * Cierra la sesión por defecto, para el thread que hace la llamada.
Text
     *
Text
     * @throws HibernateException
Text
     */
Text
    public static void closeSession() throws HibernateException {
Text
        closeSession(DEFAULT);
Text
    }
Text
}

Este código está basado en la clase de ayuda propuesta por la documentación de Hibernate en:
http://www.hibernate.org/hib_docs/v3/reference/en/html/tutorial.html#tutorial-firstapp-helpers

4. Probando la clase de ayuda

Aquí proponemos un pequeño ejemplo para probar la clase de ayuda:


Text
import org.hibernate.Session;
Text
import com.autentia.tool.HibernateMultipleConfig;
Text
public class TestHibernateMultipleConfig {
Text
    public static void main(String[] args) {
Text
        // Añadimos un nuevo fichero de configuración,
Text
        // a parte de la configuración por defecto obtenida del fichero "hibernate.cfg.xml".
Text
        // Primero indico el nombre del fichero de configuración,
Text
        // y luego la clave por la que haré referencia a esa configuración.
Text
        // Esto sólo habría que hacerlo una vez, en una fase de inicialización de la aplicación.
Text
        HibernateMultipleConfig.addConfigFile("miOtraConfiguracion.hibernate.cfg.xml", "otraConfiguracion");
Text
 
Text
 
Text
 
Text
        // Trabajamos con la sesión por defecto de hibernate.
Text
        // La sesión por defecto se obtiene del fichero "hibernate.cfg.xml".
Text
        Session defaultSession = HibernateMultipleConfig.currentSession();
Text
        // ...
Text
 
Text
        HibernateMultipleConfig.closeSession();
Text
 
Text
 
Text
 
Text
 
Text
        // Trabajamos con una sesión concreta de hibernate.
Text
        // La sesión se obtendrá a partir de la clave que se pasa como parámetro.
Text
        Session aSession = HibernateMultipleConfig.currentSession("otraConfiguracion");
Text
 
Text
        // ...
Text
 
Text
        HibernateMultipleConfig.closeSession("otraConfiguracion");
Text
    }
Text
}

5. Conclusiones

Esta clase no pretende ser perfecta ni la solución definitiva (si encontráis algún bug decírmelo ;), pero si pretende ser un buen punto de partida para la gestión de múltiples bases de datos con Hibernate.

Seguramente un buen punto a mejorar es como se cierran las sesiones. Habría que intentar facilitar un poco más la vida al desarrollador, de forma que pudiera hacer algo como “aSession.close()” y ya se realizara toda la gestión (os lo dejo como deberes). En cualquier caso no os olvidéis nunca de cerrar las sesiones (y en general de cerrar cualquier recurso: conexiones, streams, …).

Espero que os sirva de ayuda, y nos vemos en el próximo tutorial.

 

Comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

He leído y acepto la política de privacidad

Información básica acerca de la protección de datos

  • Responsable: IZERTIS S.A.
  • Finalidad: Envío información de carácter administrativa, técnica, organizativa y/o comercial sobre los productos y servicios sobre los que se nos consulta.
  • Legitimación: Consentimiento del interesado
  • Destinatarios: Otras empresas del Grupo IZERTIS. Encargados del tratamiento.
  • Derechos: Acceso, rectificación, supresión, cancelación, limitación y portabilidad de los datos.
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad

Alejandro es socio fundador de Autentia y nuestro experto en Java EE, Linux y optimización de aplicaciones empresariales. Ingeniero en Informática y Certified ScrumMaster. Seguir @alejandropgarci Si te gusta lo que ves, puedes contratarle para darte ayuda con soporte experto, impartir cursos presenciales en tu empresa o para que realicemos tus proyectos como factoría (Madrid). Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.

¿Quieres publicar en Adictos al trabajo?

Te puede interesar

30/10/2025

Benjamín Suárez Menéndez

El Complex Problem Solving (CPS) es un proceso estructurado basado en herramientas, técnicas y actitudes que nos facilita la resolución de problemas complejos.

03/10/2025

Miguel García Rodríguez

Descubre cómo el diseño y la psicología del comportamiento utilizan sesgos cognitivos para influir en la toma de decisiones de los usuarios y potenciar la persuasión.

30/09/2025

Iván García Sainz-Aja

En este artículo exploraremos cómo utilizar ZenWave360 para generar un proyecto completo de Spring Boot con Kotlin a partir de un modelo DSL de Lenguaje Ubicuo.