Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как перенести данные из одной базы данных в другую с помощью Hibernate?

Автор вопроса: cretzelОтветов: 4

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

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

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

hibernate

Ответы

Ответ 1 · рейтинг 8 · Ian McLaird

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

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

Ответ 2 · рейтинг 4 · DJ.

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

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

Ответ 3 · рейтинг 2 · Jack Leow

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

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

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

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

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

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

Ответ 4 · рейтинг 2 · Kevin Wong

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

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 );
    }
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы