せめてSQL Server 2005とSQL Server 2012であればリプリケーションを使って、片側のデータベースに対する更新を、もう片方のデータベースに反映して同期を取ることも出来るのだけど・・・と、良い方法を探していたところSymmetricDS(http://www.symmetricds.org/)というリプリケーションツールを見つけた。
SymmetricDSはJava SE6以上が動作するOSで、JDBCで接続可能なデータベース間であれば、およそ殆どの異なるアーキテクチャ間のDBを双方向にリプリケーション出来る優れものです。SQL Server 2000でも動作するはずなので、今回の用途にはぴったりです。さっそく試験環境を作成してテストしてみましょう。
1.SymmetricDSのインストール
1.1.SymmetricDSのダウンロード
SymmetricDSのホームページからzipファイルをダウンロードして、インストール先に解凍します。ここではC:\App\symmetricに解凍することにします。
1.2.ルートノードの設定ファイルを作成する
データベースへの接続設定を作成します。データベースへの接続に関する設定はC:\App\symmetric\enginesに保存します。C:\App\symmetric\samplesからcorp-000.propertiesを複製して設定します。今回はrootnode.propertiesという名称にします。
engine.nameには任意の名称を指定します。今回はrootnodeとします。
db.driverにはJDBCドライバの名称を指定します。デフォルトではH2 Databaseが指定されているので、これをコメントにしてnet.sourceforge.jtds.jdbc.Driverのコメントを外します。
db.urlには同期するデータベースへの接続文字列を指定します。デフォルトではH2 Databaseが指定されているので、これをコメントにしてjdbc:jtds:sqlserver://localhost:1433/rootdb;useCursors=true;bufferMaxMemory=10240;lobBuffer=5242880;に変更します。rootdbはデータベース名ですが、ここには日本語を指定できません。
db.userにはデータベースへのログインIDを指定します。本来はSymmetricDS用にアカウントを作るべきですが、今回はsaを指定しておきます。
db.passwordには先のログインIDで使用するパスワードを指定します。
sync.urlには同期に使用するHTTP URLを指定します。ここではhttp://localhost:31415/sync/rootnodeと指定します。sync移行に続く文字列はengine.nameで指定した文字列と一致しなくてはなりません。
group.idとexternal.idは、SymmetricDS上でデータベースを一位に識別するためのIDを指定します。ここではgroup.idをrootnode、external.idを000としておきます。
他にもパラメータがありますが、そのままにしておきます。
engine.name=rootnode
# The class name for the JDBC Driver
...#db.driver=org.h2.Driver
db.driver=net.sourceforge.jtds.jdbc.Driver
# The JDBC URL used to connect to the database
...
#db.url=jdbc:h2:corp;AUTO_SERVER=TRUE;LOCK_TIMEOUT=60000
db.url=jdbc:jtds:sqlserver://localhost:1433/rootdb;useCursors=true;bufferMaxMemory=10240;lobBuffer=5242880;
# The user to login as who can create and update tables
db.user=sa
# The password for the user to login as
db.password=xxxxxx
registration.url=
sync.url=http://localhost:31415/sync/rootdb
# Do not change these for running the demo
group.id=rootnode
external.id=000
1.3.同期対象となるノードの設定ファイルを作成する
データベースへの接続設定を作成します。データベースへの接続に関する設定はC:\App\symmetric\enginesに保存します。C:\App\symmetric\samplesからstore-000.propertiesを複製して設定します。今回はsubnode-000.propertiesという名称にします。
engine.nameには任意の名称を指定します。今回はsubnode-001とします。
db.driverにはJDBCドライバの名称を指定します。ルートノードと同じくデフォルトではH2 Databaseが指定されているので、これをコメントにしてnet.sourceforge.jtds.jdbc.Driverのコメントを外します。
db.urlには同期するデータベースへの接続文字列を指定します。ルートノードと同じくデフォルトではH2 Databaseが指定されているので、これをコメントにしてjdbc:jtds:sqlserver://localhost:1433/subdb01;useCursors=true;bufferMaxMemory=10240;lobBuffer=5242880;に変更します。
db.userにはデータベースへのログインIDを指定します。本来はSymmetricDS用にアカウントを作るべきですが、今回はsaを指定しておきます。
db.passwordには先のログインIDで使用するパスワードを指定します。
registration.urlにはルートノードsync.urlの値を指定します。ここではhttp://localhost:31415/sync/rootnodeと指定します。
group.idとexternal.idをルートノードと同様に設定します。ここではgroup.idをsubnode、external.idを001としておきます。
他にもパラメータがありますが、そのままにしておきます。
engine.name=subnode-001
# The class name for the JDBC Driver
...#db.driver=org.h2.Driver
db.driver=net.sourceforge.jtds.jdbc.Driver
# The JDBC URL used to connect to the database
...
#db.url=jdbc:h2:corp;AUTO_SERVER=TRUE;LOCK_TIMEOUT=60000
db.url=jdbc:jtds:sqlserver://localhost:1433/subdb01;useCursors=true;bufferMaxMemory=10240;lobBuffer=5242880;
# The user to login as who can create and update tables
db.user=sa
# The password for the user to login as
db.password=xxxxxx
registration.url=http://localhost:31415/sync/rootdb
# Do not change these for running the demo
group.id=subnode
external.id=001
1.4.ルートノードに制御テーブルを作成する
次のコマンドを実行してルートノードのデータベースに制御テーブルを作成します。これによりデータベースにsym~で始める各種テーブルが作成されます。制御テーブルは別のデータベースに作りたいと思うかもしれませんが、ルートノードで指定したデータベース以外の場所に作ることはできないようです。
bin\symadmin --engine rootnode create-sym-tables
続いてデータベース間の同期方法に関する設定を、上記コマンドで作成されたテーブルにINSERTします。
--既存の設定を削除。sym_channelには既定のテーブルがあるので、作成したものだけ削除するようになっています。
delete from sym_trigger_router;
delete from sym_trigger;
delete from sym_router;
delete from sym_channel where channel_id in ('tblcopy');
delete from sym_node_group_link;
delete from sym_node_group;
delete from sym_node_host;
delete from sym_node_identity;
delete from sym_node_security;
delete from sym_node;
--テーブルのコピーに使用するチャンネルを作成。
--同期でエラーが発生すると、同じチャンネルを使用しているその他の複製処理もエラーが回復するまで待たされます。
--エラーが発生しても並列して複製処理を行いたい場合には、チャンネルを複数作成します。
insert into sym_channel (channel_id, processing_order, max_batch_size, enabled, description)
values('tblcopy', 1, 100000, 1, 'Copy Sample Table');
insert into sym_node_group (node_group_id) values ('rootnode');
insert into sym_node_group (node_group_id) values ('subnode');
insert into sym_node_group_link (source_node_group_id, target_node_group_id, data_event_action) values ('rootnode', 'subnode', 'W');
insert into sym_node_group_link (source_node_group_id, target_node_group_id, data_event_action) values ('subnode', 'rootnode', 'P');
--複製の対象テーブルや複製を開始する判断条件を指定します。
--ここではワイルドカードで全てのテーブルを複製するように指定して、それ以外の項目は規定値にしています。
insert into sym_trigger
(trigger_id,source_table_name,channel_id,last_update_time,create_time)
values('tblcopy','*','tblcopy',current_timestamp,current_timestamp);
--複製の方向の指定と、複製するデータのフィルタ条件を指定します。
--複製する条件はdefaultとして全てを複製するように指示しています。
insert into sym_router (router_id,source_node_group_id,target_node_group_id,router_type,create_time,last_update_time)
values('root_2_sub', 'rootnode', 'subnode', 'default',current_timestamp, current_timestamp);
insert into sym_router (router_id,source_node_group_id,target_node_group_id,router_type,create_time,last_update_time)
values('sub_2_root', 'subnode', 'rootnode', 'default',current_timestamp, current_timestamp);
--sym_triggerとsym_routerを関連付けています。
insert into sym_trigger_router
(trigger_id,router_id,initial_load_order,last_update_time,create_time)
values('tblcopy','root_2_sub', 100, current_timestamp, current_timestamp);
--ノードの登録を行います。
insert into sym_node (node_id,node_group_id,external_id,sync_enabled,sync_url,schema_version,symmetric_version,database_type,database_version,heartbeat_time,timezone_offset,batch_to_send_count,batch_in_error_count,created_at_node_id)
values ('000','rootnode','000',1,null,null,null,null,null,current_timestamp,null,0,0,'000');
insert into sym_node (node_id,node_group_id,external_id,sync_enabled,sync_url,schema_version,symmetric_version,database_type,database_version,heartbeat_time,timezone_offset,batch_to_send_count,batch_in_error_count,created_at_node_id)
values ('001','subnode','001',1,null,null,null,null,null,current_timestamp,null,0,0,'000');
insert into sym_node_security (node_id,node_password,registration_enabled,registration_time,initial_load_enabled,initial_load_time,created_at_node_id)
values ('000','5d1c92bbacbe2edb9e1ca5dbb0e481',0,current_timestamp,0,current_timestamp,'000');
insert into sym_node_security (node_id,node_password,registration_enabled,registration_time,initial_load_enabled,initial_load_time,created_at_node_id)
values ('001','5d1c92bbacbe2edb9e1ca5dbb0e481',1,null,1,null,'000');
--ルートノードのnode_idを指定します。ルートノードは1つだけ作成します。
insert into sym_node_identity values ('000');
1.5.SymmetricDSを起動する
次のコマンドを実行してSymmetricDSを起動します。
bin\sym
正常に起動した場合、sym_~で指定したテーブルや、rootdbにある同期対象のテーブルがsubdb01に複製されデータの同期が開始されます。
2.その他TIPSなど
2.1.日本語への対応
日本語で作成したテーブル名やフィールド名があっても正常に動作しているようです。
ただしデータベース名に日本語を使用する場合はdb.urlで指定することができないので、データベースで使用するユーザーアカウントの既定のデータベースでデータベース名を指定する等の対応が必要になります。
2.2.設定に誤りがあった場合の訂正
設定に誤りがあった場合、テーブルを直接書き換えても認識して動作が変わるのですが、各テーブルに作成された中間データとの整合性が取れなくなる場合があるようで、設定が反映されない場合があります。この場合は”bin/symadmin –engine uninstall”のコマンドを実行して制御テーブルを削除し、あらためて作り直した方がよいです。
2.3.Microsoft製JDBCドライバの使用
Microsoft製JDBCドライバでも問題なく動作しています。
ただしSymmetricDSの開発サイドではjtdsのドライバを使用して動作確認しているとの事なので、そちらを利用したほうがよいでしょう。