如何使用Hibernate将数据从一个数据库传输到另一个数据库?

时间:2008-10-02 13:11:50

标签: hibernate

我有一个带有域模型的应用程序A,它使用Hibernate映射到数据库。我有另一个应用程序B使用与A完全相同的域模型类并添加一些其他类。

我的目标是从应用程序B中的数据库A读取数据,并将该数据传输到B的数据库中(以复制它)。此外,B的某些域类与A的域类有关联(OneToOne)(当然,在B的数据库中)。

实现这一目标的最佳策略是什么?我想到了两个会话工厂并使用Session.replicate()(这是如何工作的?)。或者我应该更好地在这两个域模型之间引入额外的映射层以进行松散耦合?

4 个答案:

答案 0 :(得分:8)

我之前在两种不同的数据库类型之间传输数据(在我的例子中是DB2和MS SQL Server)。我所做的是创建两个单独的会话工厂,并为它们提供相同的映射文件列表。然后我只是从一个记录中读取记录,然后将它们保存到另一个记录中。

当然,这假设两个数据源都是相同的。

答案 1 :(得分:4)

复制的目的是什么?这是您的应用程序流程或逻辑的一部分吗?或者只是直接复制数据?

如果只是为了复制数据,则无需使用休眠。它有很多工具。

答案 2 :(得分:2)

正如其他人所指出的那样,我认为我们需要确切地知道你正在努力实现的目标。如果您正在进行一次性迁移,那么有比Hibernate更好的工具来执行ETL(提取,转换,加载)。

如果你真的坚持在Hibernate中这样做(这也适用于你,Daniel),我会做类似的事情:

  1. 打开数据库A的会话。
  2. 读取您要复制的所有类型的实体(确保禁用延迟加载)
  3. 打开数据库B的会话。
  4. 保存或更新实体。
  5. 我是在一个单独的工具中完成的,而不是在应用程序A或B中。

    另一方面,如果这是应用程序功能的一部分(例如,应用程序A是数据的管理控制台,而应用程序B使用数据),您可能希望以不同的方式执行操作。如果不知道到底在找什么,很难说。

    最后,要考虑的事情(我不认为这是你正在寻找的,但也许它会帮助你以不同的方式看待你的问题)是Hibernate Shards(http://shards.hibernate.org/

答案 3 :(得分: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 );
    }
}