DBMotoを使用してOracleのデータを差分レプリケーションする場合、Redoログを参照して直接トランザクションを確認します。
しOracleの順序オブジェクト(シーケンス)はトランザクション処理ではなくRedoログに情報が記録されないため、DBMotoで普通にレプリケーションを行うことができません。
DBMotoをディザスタリカバリ等のBCP目的で使用される場合には、テーブルデータは同期が取れても順序オブジェクトの同期が取れないということになり、この場合は順序オブジェクトを手動で移動したりシーケンスの最後の値を手動で設定する等が必要になります。
しかしDBMotoの標準機能であるスクリプトを記述することで、疑似的ではありますが順序オブジェクトのレプリケーションが可能となります。
●順序オブジェクトのレプリケーションを実現させるための準備と流れ
1. ソースとターゲットのシーケンスを予め[NOCACHE]にします。
⇒ALTER SEQUENCE シーケンス名 NOCACHE
2. ソースとターゲットDBにダミーテーブルを準備します。(レコード数は0で問題ありません)
3. ダミーテーブルを使用したリフレッシュのレプリケーション定義を作成します。
4. レプリケーション定義に対してリフレッシュを定期間隔(1分おき等)で実行するようスケジュール設定します。
5. レプリケーション定義に対して、下記からダウンロード可能なスクリプトを適用します。
ダミーテーブルを使用してスケジュールリフレッシュ毎にスクリプトを実行し、スクリプトから順序オブジェクトをレプリケーションする、という流れになります。
スクリプトは下記よりダウンロードいただけます。
Imports System
Imports System.Data
Imports System.Collections
Imports Microsoft.VisualBasic
Imports DBMotoPublic
Imports DBMotoScript
Imports DBRS.GlobalScript
Namespace DBRS
Public Class SequenceName
Public owner As String
Public name As String
Public incrementBy As Integer
Public lastNumber As Integer
End Class
Public Class ReplicationScript : Inherits IReplicationScript
Dim sequenceArrayList As New ArrayList()
Public Overrides Sub Record_onBeforeMapping(recSource As IRecord, ByRef AbortRecord As Boolean)
' Do this so that no record is written to the target dummy table
AbortRecord = True
End Sub
Public Overrides Sub Refresh_onPrepareRefresh(ByRef CancelRefresh As Boolean, ByRef Filter As String)
' Here, we are identifying and initializing the sequences we want to replicate
AddLog("debug> Refresh_onPrepareRefresh()", 0)
sequenceArrayList.Clear()
' ここにスキーマ名とシーケンス名を設定します。
Dim selectCondition = "SEQUENCE_OWNER = 'schemaname' AND SEQUENCE_NAME LIKE '%SEQ%'"
Dim conn as IDbConnection = Nothing
Dim cmd as IDbCommand = Nothing
Dim reader as IDataReader = Nothing
Dim opened As Boolean = False
Try
conn = InternalSourceConnection
If conn.State <> ConnectionState.Open Then
AddLog("debug> open source connection because it hasn't been", 0)
conn.Open
opened = True
End If
cmd = conn.CreateCommand
cmd.CommandText = "SELECT SEQUENCE_OWNER, SEQUENCE_NAME, INCREMENT_BY, LAST_NUMBER FROM ALL_SEQUENCES WHERE " & selectCondition & " ORDER BY 1,2"
AddLog("debug> cmd.CommandText = " & cmd.CommandText, 0)
reader = cmd.ExecuteReader
While reader.Read
Dim seq = new SequenceName
seq.owner = reader.GetString(0)
seq.name = reader.GetString(1)
seq.incrementBy = reader.GetDecimal(2)
seq.lastNumber = reader.GetDecimal(3)
sequenceArrayList.add(seq)
AddLog("debug> " & seq.owner & "." & seq.name & " incr:" & seq.incrementBy.ToString & " lastnum: " & seq.lastNumber , 0)
End While
If sequenceArrayList.Count = 0 Then
AddLog("Warning, no sequences will be replicated.",0)
AddLog("This statement returns no rows: [" + cmd.CommandText + "]",0)
End If
Catch ex As Exception
AddLog("Exception in Internal Target Connection: " & ex.ToString,0)
Finally
If (not reader is Nothing) Then
reader.Close
End If
If (not cmd is Nothing) Then
cmd.Dispose
End If
If opened = True Then
conn.Close
End If
End Try
AddLog("debug> sequenceArrayList.Count = " & sequenceArrayList.Count.ToString, 0)
End Sub
Public Overrides Sub Refresh_onAfterRefresh()
AddLog("debug> Refresh_onAfterRefresh()...", 0)
Dim conn as IDbConnection = InternalTargetConnection
Dim cmd as IDbCommand = conn.CreateCommand
Dim cmd2 as IDbCommand = conn.CreateCommand
Dim reader as IDataReader = Nothing
Dim opened As Boolean = False
Try
If conn.State <> ConnectionState.Open Then
AddLog("debug> open target connection because it hasn't been", 0)
conn.Open
opened = True
End If
Dim seq As SequenceName
For Each seq In sequenceArrayList
cmd.CommandText = "select LAST_NUMBER from ALL_SEQUENCES where SEQUENCE_OWNER='" & seq.owner & "' AND SEQUENCE_NAME='" & seq.name & "'"
AddLog("debug> lastNumber = " & seq.lastNumber.ToString & ", target sql = " & cmd.CommandText, 0)
reader = cmd.ExecuteReader
Dim nextval As Integer = -1
If reader.Read Then
nextval = reader.GetDecimal(0)
AddLog("debug> target nextval = " & nextval.ToString, 0)
reader.Close
While (seq.incrementBy > 0 AND seq.lastNumber > nextval) OR (seq.incrementBy < 0 AND seq.lastNumber < nextval)
AddLog("debug> 1) lastNumber " & seq.lastNumber.ToString & " > nextval " & nextval.ToString, 0)
cmd2.CommandText = "select " & seq.owner & "." & seq.name & ".NEXTVAL from ALL_OBJECTS where ROWNUM <= ABS(" & ((seq.lastNumber-nextval)/seq.incrementBy).ToString & ")"
AddLog("debug> cmd2.CommandText = " & cmd2.CommandText, 0)
reader = cmd2.ExecuteReader
While reader.Read
'AddLog("debug> 2) lastNumber " & seq.lastNumber.ToString & " > nextval " & nextval.ToString, 0)
nextval = reader.GetDecimal(0)+seq.incrementBy
End While
reader.Close
End While
End If
Next
Catch ex As Exception
AddLog("Exception in Internal Target Connection: " & ex.ToString,0)
Finally
if (not reader is Nothing) Then
reader.Close
End If
if (not cmd is Nothing) Then
cmd.Dispose
End If
If opened = True Then
conn.Close
End If
End Try
End Sub
End Class
End Namespace
●スクリプトの内容
1. ソースとターゲット側のシーケンスの最後の値を抽出します。
2. 両者の値を比較し、【ソース>ターゲット】の場合には【ソース=ターゲット】になるまで、ターゲット側のシーケンスに対してNEXTVALを実行します。
●スクリプト適用手順
メタデータは下記の構成となっています。
・テーブル「EMPLOYEE」が順序オブジェクトの疑似レプリケーション用ダミーテーブル(レコードはなし)
・テーブル「TABLE1」が順序オブジェクトを使用している実テーブル
・レプリケーション「TABLE1」が、実テーブルTABLE1のミラーリング構成
・レプリケーション「順序レプリケーション」は、ダミーテーブルEMPLOYEEのリフレッシュ構成
⇒これに対してスクリプトを適用します。

リフレッシュスケジュールを1分間隔で実行するよう設定します。

「スクリプトを使用」にチェックを入れ、スクリプト画面を開きます。

スクリプトをコピーして適用します。

関連したトピックス
- ミラーリングおいてのレコード数を確認の方法【リアルタイムレプリケーションツールDBMoto】
- 2つのソーステーブルからターゲットの一つのレコードにレプリケーション
- [Syniti(旧DBMoto)]レコード競合(コンフリクト)発生時のレコード内容を出力する方法
- [DBMoto][スクリプト]条件付きレプリケーションを行うサンプルVBスクリプト
- [DBMoto]関数を使用してレプリケーション時のデータを変換する方法(VB/C#言語選択、関数適用、ユーザ関数作成、置換関数、一括設定手順)
- レプリケーションの際にnullを特定の値に変換する方法 その2【リアルタイムレプリケーションツールDBMoto】
- [DBMoto][スクリプト]カラムを結合・分割したレプリケーション
- [DBMoto]「未マッピング使用」機能によるマッピング外のデータを活用したレプリケーション
- 複数の複製元サーバから1つの複製先サーバへの結合レプリケーションもDBMotoで簡単実現
- 複数のテーブルにあるレコードを1つのテーブルへ統合する際の注意点【リアルタイムレプリケーションツールDBMoto】

RSSフィードを取得する