2008-10-02 4 views
8

J'ai une application A avec un modèle de domaine qui est mappé à une base de données en utilisant Hibernate. J'ai une autre application B qui utilise exactement les mêmes classes de modèles de domaines que A et ajoute des classes supplémentaires.Comment transférer des données d'une base de données à une autre avec Hibernate?

Mon but est de lire les données de la base de données A dans l'application B et de transférer ces données dans la base de données de B (pour en faire une copie). De plus, certaines classes de domaine de B ont des associations (OneToOne) aux classes de domaine de A (mais dans la base de données de B, bien sûr).

Quelle est la meilleure stratégie pour y parvenir? J'ai pensé à deux usines de session et en utilisant Session.replicate() (comment ça marche?). Ou devrais-je mieux introduire une couche de mappage supplémentaire entre ces deux modèles de domaine pour un couplage lâche?

Répondre

7

Je l'ai déjà fait pour transférer des données entre deux types de bases de données différents (dans mon cas, DB2 et MS SQL Server). Ce que j'ai fait était de créer deux usines de sessions séparées, et de leur donner la même liste de fichiers de mapping. Ensuite, j'ai simplement lu les enregistrements d'un, et les a sauvés à l'autre.

Bien entendu, cela supposait que les deux sources de données étaient identiques.

+0

J'essaie cela, mais j'ai rencontré un problème avec les relations circulaires.Étudié en désactivant les contraintes DB de destination, mais n'a pas pu trouver un moyen évident de le faire. Vous devrez peut-être écrire du code personnalisé pour supprimer/reconstruire les relations incriminées. –

3

Quel est le but de la copie? Cela fait-il partie de votre flux d'applications ou de votre logique? ou simplement copier des données directement?

Si vous souhaitez simplement copier des données, il n'est pas nécessaire d'utiliser le mode hibernation. Il y a beaucoup d'outils pour cela.

+0

Exemples/recommandations s'il vous plaît. Tout ce qui peut être initié par programme? –

2

Comme d'autres l'ont souligné, je pense que nous devons savoir exactement ce que vous essayez d'accomplir. Si vous effectuez une migration ponctuelle, il existe de meilleurs outils qu'Hibernate pour effectuer l'ETL (Extract, Transform, Load).

Si vous insistez vraiment faire cela dans Hibernate (cela vaut pour vous aussi, Daniel), je ferais quelque chose comme:

  1. Audience publique à la base de données A.
  2. Lire toutes les entités du tapez que vous essayez de copier (assurez-vous que le chargement paresseux est désactivé)
  3. Ouvrir la session à la base de données B.
  4. Enregistrer ou mettre à jour les entités.

Je ferais cela dans un outil distinct, plutôt que dans l'application A ou B.

D'autre part, si cela fait partie de la fonctionnalité de vos applications (par exemple, l'application A est le console d'administration aux données, tandis que l'application B consomme les données), vous voudrez peut-être faire les choses un peu différemment. C'est difficile à dire sans savoir exactement ce que vous cherchez. Enfin, quelque chose à regarder (je ne pense pas que ce soit ce que vous cherchez, mais peut-être que cela vous aidera à voir votre problème d'une manière différente) est Hibernate Shards (http://shards.hibernate.org/).

2

Essayé d'autres outils et rencontré des problèmes. Voici ma solution maison-roulée. Peut-être besoin d'un peu de nettoyage, mais la viande est là.

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'est ce que l'importation ca.digitalrapids.lang.GeneralException? Impossible de le trouver n'importe où – john

+0

@john https://en.wikipedia.org/wiki/Digital_Rapids_Corporation - est-il possible que ce soit une bibliothèque propriétaire? (J'espère que non, cela semblerait rendre la réponse beaucoup moins utile si cela dépend des bibliothèques qui ne sont pas publiquement disponibles). – EJoshuaS

+0

@EJoshuaS Je pense que c'est. ma pensée est: cette réponse a obtenu deux upvotes. Cela signifie qu'au moins deux personnes savent ce que sont ces bibliothèques et pourraient partager les liens avec ces bibliothèques avec nous – john