2008-10-02 4 views
8

У меня есть приложение A с доменной моделью, которая сопоставляется с базой данных с использованием Hibernate. У меня есть другое приложение B, которое использует точно такие же классы доменных моделей, что и A, и добавляет некоторые дополнительные классы.Как перенести данные из одной базы данных в другую с помощью Hibernate?

Моя цель - считывать данные из базы данных A в приложении B и передавать эти данные в базу данных B (чтобы сделать ее копию). Кроме того, некоторые доменные классы B имеют ассоциации (OneToOne) с доменными классами A (но в базе данных B, конечно).

Какова наилучшая стратегия для достижения этой цели? Я думал о двух сессионных фабриках и использовал Session.replicate() (как это работает?). Или мне лучше ввести дополнительный слой сопоставления между этими двумя доменными моделями для свободной связи?

ответ

7

Я делал это раньше, чтобы передавать данные между двумя разными типами баз данных (в моем случае DB2 и MS SQL Server). То, что я сделал, было создание двух отдельных сессионных фабрик, и дать им обоим один и тот же список файлов сопоставления. Затем я просто читал записи от одного и сохранял их в другом.

Конечно, предполагается, что оба источника данных были идентичны.

+0

Я пытаюсь это сделать, но столкнулся с проблемой круговых отношений.Исследуется отключение ограничений dest DB, но не удалось найти очевидный способ сделать это. Может потребоваться написать собственный код для удаления/восстановления отношений с нарушением. – 2012-09-27 15:55:31

3

Какова цель копирования? Это часть вашего потока приложений или логики? или просто прямое копирование данных?

Если это просто для копирования данных, нет необходимости использовать спящий режим. Для этого есть множество инструментов.

+0

Примеры/рекомендации, пожалуйста. Все, что может быть инициировано программно? – 2012-09-27 15:56:47

2

Как и другие, я думаю, нам нужно точно знать, что именно вы пытаетесь выполнить. Если вы выполняете одноразовую миграцию, там есть лучшие инструменты, чем Hibernate, чтобы делать ETL (Extract, Transform, Load).

Если вы действительно настаиваете на этом в Hibernate (это относится и к вам также, Даниил), я бы что-то вроде:

  1. Открыть сессию в базу данных А.
  2. Читать все подразделения тип, который вы пытаетесь скопировать (убедитесь, что ленивая загрузка отключена)
  3. Открытый сеанс связи с базой данных B.
  4. Сохраните или обновите объекты.

Я хотел бы сделать это в отдельном инструменте, а не в приложении А или В.

С другой стороны, если это является частью функциональности приложений (например, приложение А является админ-консоли к данным, в то время как приложение B потребляет данные), вы можете сделать что-то по-другому. Трудно сказать, не зная, что именно вы ищете.

И, наконец, что-то заглянуть (я не думаю, что это то, что вы ищете, но, возможно, это поможет вам разобраться с вашей проблемой по-другому) - Hibernate Shards (http://shards.hibernate.org/).

2

Пробовал другие инструменты и имел проблемы. Вот мое домашнее решение. Может потребоваться очистка, но мясо там есть.

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

Что такое импорт ca.digitalrapids.lang.GeneralException? Не могу найти его нигде. – john 2017-01-09 23:16:19