親子関係のテーブル構造ごと、別のデータベースに転送する X-R マッピング
データベース間のデータ転送をするとき、親子関係のテーブル構造を、そのまま転送する方法。
メッセージングで、データベース間を連携するとき、親子関係のテーブル(たとえば、受注ヘッダと受注明細)を、そのままの構造で転送することがなかなかできずに困っていた。
親レコードと子レコードをばらばらに送ると、非同期なので、受け取った側のデータベースに書き込む時、参照整合性とかやっかいな問題がおきる。
結合して、一つのフラットファイルのイメージで、メッセージとして送る方法もある。これは、受け取った側で、親子関係の分解が面倒。
アイデアとしては、親子関係の構造を、そのままXML ドキュメントにマッピングして、転送すれば良いとは思っていたが、記述が複雑になりそうで、避けていた。
今回、どうしても、そういう機能がほしくなり、Mule ESB + groovy スクリプトで、書いてみたら、意外と簡単に実現できた。
Mule ESB のサービス構成
<model name="db-xml-db Sample"> <service name="db to xml"> <inbound> <jdbc:inbound-endpoint pollingFrequency="${jdbc.pollingFrequency}" queryKey="requestPolling"/> </inbound> <script:component> <script:script name="select and build xml" engine="groovy" file="script/db-xml.groovy" /> </script:component> <outbound> <pass-through-router> <vm:outbound-endpoint address="vm://save"/> </pass-through-router> </outbound> </service> <service name="xml to databese"> <inbound> <vm:inbound-endpoint address="vm://save"/> </inbound> <script:component> <script:script name="parse xml and insert" engine="groovy" file="script/xml-db.groovy" /> </script:component> </service> </model>
//payload から 転送すべき id を取得 id = payload.id def writer = new StringWriter() def xmlDocument = new groovy.xml.MarkupBuilder( writer ) // 親・子・孫のSELECTをしながら XML 生成 // // xmlDocument.要素名( SELECT結果 ) の形式で、 // その要素名で、xml 要素を生成 // SELECT結果を、その要素の属性に、カラム名="値", ... 形式で記述 // // 親レコード(XMLルート要素)を一件だけ取得する // 複数行文字列は、トリプルクォートで記述 def oyaRecord = sql.firstRow( "親レコードSELECT文" ) xmlDocument.oya( oyaRecord ){ // oya要素 生成 def listOfKo = sql.rows( "子レコードSELECT文" ) ; listOfKo.each{ koRecord -> xmlDocument.ko( koRecord ) { // ko要素 生成 def listOfMago = sql.rows( "孫レコード取得SELECT文" ) ; listOfMago.each{ magoRecord -> xmlDocument.mago( magoRecord ) } // mago要素生成 } } } xmlMessage = writer.toString() // xml をStringオブジェクトに変換 log.info( "XML送信:$xmlMessage" ) return xmlMessage // outbound に xmlMessage を渡す
生成した XML
<oya id='1' name='oya1'> <ko id='1' oya_id='1' name='ko1'> <mago id='1' ko_id='1' name='mago1' /> <mago id='2' ko_id='1' name='mago2' /> </ko> <ko id='2' oya_id='1' name='ko2'> <mago id='3' ko_id='2' name='mago3' /> <mago id='4' ko_id='2' name='mago4' /> </ko> </oya>
xml to db の groovy スクリプト ( 抜粋 )
// payload から xml 要素を取り出しながら、データベースに出力 // groovy XmlParse // xml 要素名を、そのままオブジェクト名として参照できる def oya = new XmlParser().parseText(payload); insertOya( oya.attributes() ) oya.each { ko -> insertKo( ko.attributes() ) ko.each { mago -> insertMago( mago.attributes() ) } } def insertOya(map){ /* insert 文の実行 */ } def insertKo(map){ /* insert 文の実行 */ } def insertMago(map){ /* insert 文の実行 */ }
goovy の xml.MarkupBuilder、 util.XMLParser クラスを使うと、こんな感じで、書けちゃう。
親子関係だけではなく、2階層目に異なる要素(つまり、兄弟関係の要素)の構造でも、同じ感じで、書ける。
X-R マッピングが、こんなに簡単にかければ、いろいろ使えそうです。
参考URL:
実用的な Groovy: XML を作成し、構文解析し、容易に扱う
http://www.liquibase.org/ja/generate-changelog-with-groovy