« [ゴータマ]なまぐさについて | メイン | Hibernate Validatorを使う »

Hibernate Shardsをちょっと触る

Hibernate Shardsは、複数のRDBにデータを分割してI/Oする仕組みをHibernateで実現するものです。
ほんの少しだけ触ってみました。変わったことは何もしていません。Hello Worldレベル。

  1. 必要なライブラリ
  2. Hibernate Shardsを用いるにはHibernate Coreが必要なので、
    • Core本体
    • Coreが依存するlib
    • Shardsのlib
    を入れる。試すJDBCドライバーも含める。

    +lib
     antlr.jar
     cglib.jar
     asm.jar
     asm-attrs.jars
     commons-collections.jar
     commons-logging.jar
     hibernate3.jar
     hibernate-shards.jar
     jta.jar
     dom4j.jar
     log4j.jar
     JDBCドライバーのjar

  3. RDBMSの設定

  4. Hibernate Shardsは複数のRDBMSに対してデータを分散して登録する。そのためにhibernateの設定ファイルをRDBMS分用意する。

    db1.hibernate.cfg.xml

    <hibernate-configuration>
     <session-factory name="sf0">
      <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
      <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
      <property name="connection.username">sa</property>
      <property name="connection.password"></property>
      <property name="connection.url">jdbc:hsqldb:hsql://localhost:9001</property>
      <property name="hibernate.connection.shard_id">0</property>
      <property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property>
      <property name="hbm2ddl.auto">create</property>
    ・・・
     </session-factory>
    </hibernate-configuration>

    db2.hibernate.cfg.xml

    <hibernate-configuration>
     <session-factory name="sf1">
      <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
      <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
      <property name="connection.username">sa</property>
      <property name="connection.password"></property>
      <property name="connection.url">jdbc:hsqldb:hsql://localhost:9002</property>
      <property name="hibernate.connection.shard_id">1</property>
      <property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property>
     <property name="hbm2ddl.auto">create</property>
    ・・・
     </session-factory>
    </hibernate-configuration>

    hibernate.connection.shard_idは、複数のRDBを識別する識別子となるので、かぶらないように別々の番号を振る。session-factorynameもかぶらないようにつけておく必要があるっぽい。


  5. エンティティとマッピングファイル
  6. エンティティを用意する。簡単に試したいのでidとvalueのみの単純なエンティティを使う。

    package net.grandnature.example.invoice.entity;

    public class Example {
     private Long id;
     private String value;
     public Long getId() {
      return id;
     }
     public void setId(Long id) {
      this.id = id;
     }
     public String getValue() {
      return value;
     }
     public void setValue(String value) {
      this.value = value;
     }
    }

    マッピングファイルはこんな感じ。

    example.hbm.xml

    <hibernate-mapping package="net.grandnature.example.invoice.entity">
     <class name="Example">
      <id name="id" type="long">
       <generator class="org.hibernate.shards.id.ShardedTableHiLoGenerator"/>
      </id>
      <property name="value"/>
     </class>
    </hibernate-mapping>

    ShardedTableHiLoGeneratorを用いると複数のRDBMSでHiloの値が重複しないようになる。identityなどで行いたい場合は、ひとつめのDBは0からはじまるように、ふたつめのDBでは1000からはじまるように、など、データ量に応じてIDが重複しないように自分でうまく調節する必要がある模様。

    ShardedTableHiLoGeneratorをHibernate Annotationでgeneratorとして指定するにはどうすればいいのかなあ。

  7. データを登録してみる
  8. public class ShardsExample {
     public static void main(String[] args) {
      new ShardsExample().insert();
     }

     void insert() {
      Session session = createSessionFactory().openSession();
      Transaction tx = session.beginTransaction();
      for (int i = 0; i < 10; i++) {
       Example example1 = new Example();
       example1.setValue(i + "番目");
       session.save(example1);
      }
      tx.commit();
      session.close();
     }

     SessionFactory createSessionFactory() {
      Configuration prototype = new Configuration().configure("db1.hibernate.cfg.xml");
      prototype.addResource("example.hbm.xml");
      List shard = new ArrayList();
      shard.add(new Configuration().configure("db1.hibernate.cfg.xml"));
      shard.add(new Configuration().configure("db2.hibernate.cfg.xml"));
      ShardStrategyFactory shardStrategyFactory = buildShardStrategyFactory();
      ShardedConfiguration shardedConfig = new ShardedConfiguration(
        prototype, shard, shardStrategyFactory);
      return shardedConfig.buildShardedSessionFactory();
     }

     ShardStrategyFactory buildShardStrategyFactory() {
      ShardStrategyFactory shardStrategyFactory = new ShardStrategyFactory() {
       public ShardStrategy newShardStrategy(List shardIds) {
        RoundRobinShardLoadBalancer loadBalancer = new RoundRobinShardLoadBalancer(
          shardIds);
        ShardSelectionStrategy pss = new RoundRobinShardSelectionStrategy(
          loadBalancer);
        ShardResolutionStrategy prs = new AllShardsShardResolutionStrategy(
          shardIds);
        ShardAccessStrategy pas = new SequentialShardAccessStrategy();
        return new ShardStrategyImpl(pss, prs, pas);
       }
      };
      return shardStrategyFactory;
     }
    }

    これを実行すると、db1.hibernate.cfg.xmlにて定義したRDBに

    ID:1, VALUE:0番目
    ID:2, VALUE:2番目
    ID:3, VALUE:4番目
    ID:4, VALUE:6番目
    ID:5, VALUE:8番目

    が入り、db2.hibernate.cfg.xmlにて定義したRDBに

    ID:32768, VALUE:1番目
    ID:32769, VALUE:3番目
    ID:32770, VALUE:5番目
    ID:32771, VALUE:7番目
    ID:32772, VALUE:9番目


    が入る。(例えばの話)

  9. データを取得してみる
  10.  void select() {
      SessionFactory sessionfactory = createSessionFactory();
      Session session = sessionfactory.openSession();
      List list = session.createQuery(" FROM Example ").list();
      for (Example example : (List) list) {
       System.out.println("ID:" + example.getId() + ", VALUE:" + example.getValue());
      }
     }

    単一のRDBを操作する場合と変わらない。複数のRDBであることを意識することなく取得できる。

  11. ShardAccessStrategyを別のものに換えてみる
  12. ShardAccessStrategyとは、データベースへのオペレーションを複数のRDBに対してどのように適用するかを定めたもの。現在の例はSequentialShardAccessStrategyを使っている。SequentialShardAccessStrategyは、複数のRDBに対してひとつずつ順番に処理を実行していく。これをParallelShardAccessStrategyに変更してみる。ParallelShardAccessStrategyはスレッドを生成し、複数のRDBに対して並列に処理を行う。

    変更したbuildShardStrategyFactory

    ShardStrategyFactory buildShardStrategyFactory() {
     ShardStrategyFactory shardStrategyFactory = new ShardStrategyFactory() {
      public ShardStrategy newShardStrategy(List shardIds) {
       RoundRobinShardLoadBalancer loadBalancer = new RoundRobinShardLoadBalancer(shardIds);
       ShardSelectionStrategy pss = new RoundRobinShardSelectionStrategy(loadBalancer);
       ShardResolutionStrategy prs = new AllShardsShardResolutionStrategy(shardIds);
       ThreadFactory factory = new ThreadFactory() {
        public Thread newThread(Runnable r) {
         Thread t = Executors.defaultThreadFactory().newThread(r);
         t.setDaemon(true);
         return t;
        }
       };
       ThreadPoolExecutor exec = new ThreadPoolExecutor(10, 50, 60,TimeUnit.MICROSECONDS,
         new SynchronousQueue(), factory);
       ShardAccessStrategy pas = new ParallelShardAccessStrategy(exec);
       return new ShardStrategyImpl(pss, prs, pas);
      }
     };
     return shardStrategyFactory;
    }

トラックバック

このエントリーのトラックバックURL:
http://www.grandnature.net/bin/mt-tb.cgi/32

コメントを投稿

About

2007年04月06日 16:22に投稿されたエントリーのページです。

ひとつ前の投稿は「[ゴータマ]なまぐさについて」です。

次の投稿は「Hibernate Validatorを使う」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。