9

Hibernateを使用してデータベースにマップされたドメインモデルを持つアプリケーションAがあります。A とまったく同じドメイン モデル クラスを使用し、いくつかの追加クラスを追加する別のアプリケーション B があります。

私の目標は、アプリケーション B のデータベース A からデータを読み取り、そのデータを B のデータベースに転送する (コピーを作成する) ことです。さらに、B のいくつかのドメインクラスは、A のドメインクラスに関連付け (OneToOne) を持っています (ただし、もちろん B のデータベース内にあります)。

これを達成するための最良の戦略は何ですか? 私は 2 つのセッション ファクトリと使用を考えましたSession.replicate()(それはどのように機能しますか?)。それとも、疎結合のためにこれら 2 つのドメイン モデル間に追加のマッピング レイヤーを導入する必要がありますか?

4

4 に答える 4

8

これは、2 つの異なるデータベース タイプ (私の場合は DB2 と MS SQL Server) 間でデータを転送するために行ったことがあります。私が行ったことは、2 つの別個のセッション ファクトリを作成し、それらの両方に同じマッピング ファイルのリストを与えることでした。次に、一方からレコードを読み取り、もう一方に保存しました。

もちろん、これは両方のデータ ソースが同一であることを前提としています。

于 2008-10-06T20:21:09.483 に答える
4

コピーの目的は何ですか?それはアプリケーション フローまたはロジックの一部ですか? または単にデータをコピーするだけですか?

データをコピーするだけの場合は、休止状態を使用する必要はありません。そのためのツールはたくさんあります。

于 2008-10-03T01:43:43.260 に答える
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 );
    }
}
于 2012-09-28T06:14:03.213 に答える
2

他の人が指摘したように、あなたが達成しようとしていることを正確に知る必要があると思います. 1 回限りの移行を行っている場合、ETL (抽出、変換、読み込み) を行うための Hibernate よりも優れたツールがあります。

Hibernate でこれを行うことを本当に主張する場合 (これはダニエルにも当てはまります)、私は次のようにします。

  1. データベース A へのセッションを開きます。
  2. コピーしようとしているタイプのすべてのエンティティを読み取ります (遅延読み込みが無効になっていることを確認してください)
  3. データベース B へのセッションを開きます。
  4. エンティティを保存または更新します。

これは、アプリケーション A または B ではなく、別のツールで行います。

一方、これがアプリケーションの機能の一部である場合 (たとえば、アプリケーション A がデータの管理コンソールであり、アプリケーション B がデータを消費する場合)、少し異なる方法で処理したい場合があります。正確に何を探しているのかを知らずに言うのは難しいです。

最後に、調べる必要があるもの (これはあなたが探しているものではないと思いますが、問題を別の方法で見るのに役立つかもしれません) は Hibernate Shards ( http://shards.hibernate.org / )。

于 2008-10-31T15:04:44.330 に答える