2008-10-02 33 views
8

Tengo una aplicación A con un modelo de dominio que se asigna a una base de datos usando Hibernate. Tengo otra aplicación B que usa exactamente las mismas clases de modelo de dominio que A y agrega algunas clases adicionales.¿Cómo transferir datos de una base de datos a otra con Hibernate?

Mi objetivo es leer los datos de la base de datos A en la aplicación B y transferir esos datos a la base de datos de B (para hacer una copia). Además, algunas clases de dominio de B tienen asociaciones (OneToOne) con clases de dominio de A (pero en la base de datos de B, por supuesto).

¿Cuál es la mejor estrategia para lograr esto? Pensé en dos fábricas de sesión y el uso de Session.replicate() (¿cómo funciona eso?). ¿O debería introducir una capa de mapeo adicional entre estos dos modelos de dominio para un acoplamiento flexible?

Respuesta

7

He hecho esto antes para transferir datos entre dos tipos de bases de datos diferentes (en mi caso, DB2 y MS SQL Server). Lo que hice fue crear dos fábricas de sesión separadas y darles a ambas la misma lista de archivos de mapeo. Luego simplemente leí los registros de uno y los guardé en el otro.

Por supuesto, esto supone que ambas fuentes de datos son idénticas.

+0

Estoy intentando esto, pero me he encontrado con un problema con las relaciones circulares.Se investigó la desactivación de las limitaciones de la base de datos de dest ina, pero no se pudo encontrar una forma obvia de hacerlo. Puede que tenga que escribir un código personalizado para eliminar/reconstruir las relaciones ofensivas. –

3

¿Cuál es el propósito de la copia? ¿Es eso parte de tu flujo de aplicaciones o lógica? o simplemente copiar datos directamente?

Si solo se trata de copiar datos, no es necesario utilizar hibernate. Hay muchas herramientas para eso.

+0

Ejemplos/recomendaciones por favor. ¿Algo que pueda iniciarse programáticamente? –

2

Como han señalado otros, creo que necesitamos saber exactamente qué es lo que estás tratando de lograr. Si realiza una migración única, existen mejores herramientas que Hibernate para hacer ETL (Extraer, Transformar, Cargar).

Si realmente insisten en hacer esto en Hibernate (esto se aplica a usted también, Daniel), me gustaría hacer algo como:

  1. Sesión abierta a la base de datos A.
  2. Leer todas las entidades del escriba que está intentando copiar (asegúrese de que la carga diferida esté deshabilitada)
  3. Abra la sesión en la base de datos B.
  4. Guarde o actualice las entidades.

me gustaría hacer esto en una herramienta independiente, en lugar de en la solicitud A o B.

Por otro lado, si esto es parte de la funcionalidad de las aplicaciones (por ejemplo, la aplicación A es el consola de administración a los datos, mientras que la aplicación B consume los datos), es posible que desee hacer las cosas de manera un poco diferente. Es difícil de decir sin saber exactamente qué estás buscando.

Finalmente, algo a considerar (no creo que esto sea lo que estás buscando, pero quizás te ayude a ver tu problema de otra manera) es Hibernate Shards (http://shards.hibernate.org/).

2

Intenté otras herramientas y tuve problemas. Aquí está mi solución rodada en casa. Puede necesitar un poco de limpieza, pero la carne está allí.

import java.io.Serializable; 
import java.util.List; 
import java.util.logging.Logger; 

import lombok.Getter; 
import lombok.RequiredArgsConstructor; 
import lombok.Setter; 

import org.hibernate.Session; 
import org.hibernate.Transaction; 

import ca.digitalrapids.lang.GeneralException; 
import ca.digitalrapids.mediamanager.server.dao.hibernate.GenericDAOHibernate; 
import ca.digitalrapids.mediamanager.server.dao.hibernate.GenericDAOHibernate.GenericDAOHibernateFactory; 
import ca.digitalrapids.persist.dao.DAOOptions; 
import ca.digitalrapids.persist.hibernate.HibernateUtil2; 

import com.google.common.collect.ImmutableMultimap; 
import com.google.common.collect.ImmutableSet; 
import com.google.common.collect.Sets; 

@RequiredArgsConstructor 
public class DataMigrator 
{ 
    private static final Logger logger = Logger 
     .getLogger(DataMigrator.class.getName()); 
    private final HibernateUtil2 sourceHibernateUtil2; 
    private final HibernateUtil2 destHibernateUtil2; 
    private final ImmutableSet<Class<?>> beanClassesToMigrate; 
    @Setter @Getter 
    private Integer copyBatchSize = 10; 
    @Setter 
    private GenericDAOHibernateFactory sourceDaoFactory = 
     new GenericDAOHibernate.GenericDAOHibernateFactoryImpl(); 
    @Setter 
    private GenericDAOHibernateFactory destDaoFactory = 
     new GenericDAOHibernate.GenericDAOHibernateFactoryImpl(); 
    private final ImmutableMultimap<Class<?>, Class<?>> entityDependencies; 

    public void run() throws GeneralException 
    { 
     migrateData(sourceHibernateUtil2.getSession(), 
      destHibernateUtil2.getSession()); 
    } 

    private void migrateData(Session sourceSession, Session destSession) 
     throws GeneralException 
    { 
     logger.info("\nMigrating data from old HSQLDB database.\n"); 

     Transaction destTransaction = null; 
     try 
     { 
      destTransaction = destSession.beginTransaction(); 
      migrateBeans(sourceSession, destSession, beanClassesToMigrate, 
       entityDependencies); 
      destTransaction.commit(); 
     } catch (Throwable e) { 
      if (destTransaction != null) 
       destTransaction.rollback(); 
      throw e; 
     } 

     logger.info("\nData migration complete!\n"); 
    } 



    private void migrateBeans(Session sourceSession, Session destSession, 
     ImmutableSet<Class<?>> beanClasses, ImmutableMultimap<Class<?>, Class<?>> deps) 
    { 
     if (beanClasses.isEmpty()) return; 
     Class<?> head = beanClasses.iterator().next(); 
     ImmutableSet<Class<?>> tail = 
      Sets.difference(beanClasses, ImmutableSet.of(head)).immutableCopy(); 
     ImmutableSet<Class<?>> childrenOfHead = getChildren(head, tail, deps); 
     migrateBeans(sourceSession, destSession, childrenOfHead, deps); 
     migrateBean(sourceSession, destSession, head); 
     migrateBeans(sourceSession, destSession, 
      Sets.difference(tail, childrenOfHead).immutableCopy(), deps); 
    } 

    private ImmutableSet<Class<?>> getChildren(Class<?> parent, 
     ImmutableSet<Class<?>> possibleChildren, 
     ImmutableMultimap<Class<?>, Class<?>> deps) 
    { 
     ImmutableSet<Class<?>> parentDeps = ImmutableSet.copyOf(deps.get(parent)); 
     return Sets.intersection(possibleChildren, parentDeps).immutableCopy(); 
    } 

    private void migrateBean(Session sourceSession, Session destSession, 
     Class<?> beanClass) 
    { 
     GenericDAOHibernate<?, Serializable> sourceDao = 
      sourceDaoFactory.get(beanClass, sourceSession); 
     logger.info("Migrating "+sourceDao.countAll()+" of "+beanClass); 

     DAOOptions options = new DAOOptions(); 
     options.setMaxResults(copyBatchSize); 
     List<?> sourceBeans; 
     int firstResult = 0; 
     int sourceBeansSize; 
     do { 
      options.setFirstResult(firstResult); 
      sourceBeans = sourceDao.findAll(options); 
      sourceBeansSize = sourceBeans.size(); 
      @SuppressWarnings("unchecked") 
      GenericDAOHibernate<Object, Serializable> destDao = 
       (GenericDAOHibernate<Object, Serializable>) 
       destDaoFactory.get(beanClass, destSession); 
      for (Object sourceBean : sourceBeans) 
      { 
       destDao.save(sourceBean); 
      } 
      firstResult += copyBatchSize; 
      sourceSession.clear();/* prevent memory problems */ 
     } while (sourceBeansSize >= copyBatchSize); 
    } 
} 
+2

¿Qué es la importación ca.digitalrapids.lang.GeneralException? No se puede encontrar en ningún lado – john

+0

@john https://en.wikipedia.org/wiki/Digital_Rapids_Corporation - ¿Es posible que se trate de una biblioteca propia? (Espero que no, eso parecería hacer la respuesta mucho menos útil si depende de las bibliotecas que no están disponibles públicamente). – EJoshuaS

+0

@EJoshuaS, creo que es. mi pensamiento es: esta respuesta tiene dos votos favorables. Esto significa que al menos dos personas saben cuáles son esas bibliotecas y podrían compartir los enlaces a esas bibliotecas con nosotros. – john

Cuestiones relacionadas