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

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

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

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


person cretzel    schedule 02.10.2008    source источник


Ответы (4)


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

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

person Ian McLaird    schedule 06.10.2008
comment
Я пытаюсь это сделать, но столкнулся с проблемой круговых отношений. Исследовал отключение ограничений целевой БД, но не смог найти очевидный способ сделать это. Возможно, придется написать собственный код для удаления/восстановления оскорбительных отношений. - person Kevin Wong; 27.09.2012
comment
нам нужно «читать» записи явно. Есть ли возможность просто скопировать ВСЕ записи из одной БД в другую? - person phoenixSid; 01.11.2018
comment
@phoenixSid - я не знаю, как это сделать с помощью спящего режима без явного чтения всех записей. Если вы просто хотите скопировать данные из одного места в другое, это, вероятно, не лучшее решение. - person Ian McLaird; 01.11.2018
comment
@IanMcLaird Спасибо! - person phoenixSid; 01.11.2018

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

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

person DJ.    schedule 03.10.2008
comment
Примеры/рекомендации пожалуйста. Что-нибудь, что можно инициировать программно? - person Kevin Wong; 27.09.2012

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

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

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

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

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

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

person Jack Leow    schedule 31.10.2008

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

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 );
    }
}
person Kevin Wong    schedule 28.09.2012
comment
что такое импорт ca.digitalrapids.lang.GeneralException? нигде не могу найти - person john; 10.01.2017
comment
@john en.wikipedia.org/wiki/Digital_Rapids_Corporation - возможно ли, что это какая-то частная библиотека? (Надеюсь, что нет, это может сделать ответ намного менее полезным, если он зависит от библиотек, которые не являются общедоступными). - person EJoshuaS - Reinstate Monica; 15.01.2017
comment
@EJoshuaS, я думаю, что да. я думаю: этот ответ получил два голоса. Это означает, что как минимум два человека знают, что это за библиотеки, и могут поделиться с нами ссылками на эти библиотеки. - person john; 16.01.2017