Как перенести данные из одной базы данных в другую с помощью Hibernate? - PullRequest
8 голосов
/ 02 октября 2008

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

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

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

Ответы [ 4 ]

8 голосов
/ 07 октября 2008

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

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

4 голосов
/ 03 октября 2008

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

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

2 голосов
/ 28 сентября 2012

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

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 голосов
/ 31 октября 2008

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

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

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

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

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

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

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