こんにちは。CData Software Japanリードエンジニアの杉本です。
今回はCData Salesforce Driverを使いこなす上で一つのポイントとなる、一括処理方法について解説したいと思います。
CData Driverにおける一括処理のポイント
まず「なぜ一括でのレコード処理について解説するのか?」についておさえておきましょう。
CData Driverの多くはその性質上、様々なクラウドサービスのAPIへの処理をサポートしています。
そこでポイントになるのは通常のRDB接続とは異なり、APIがサポートしている範囲がパフォーマンとして高められるポイントや上限になるということです。
例えばAPIが1レコード毎の作成しかサポートしていないのであれば、CData Driverを用いても、1レコードの作成を都度行うことしかできません。
しかしながら、APIが複数レコードの作成をサポートしているものであれば、多くのCData Driverが複数のレコードを同時にリクエストする方法をサポートしており、一括で処理ができるようになっています。(もちろん例外もあります)
これによりAPIのリクエスト数を抑えたり、効率よくレコードの作成や更新を行うことができます。
今回紹介するSalesforce Driverの機能も同様で、一括処理を行うことができる機能が提供されていますので、この機能を適切に用いることで効率的かつ以前の記事で紹介したようなAPI Limitをうまく抑えながら、APIを利用できるようになります。
それでは実際に使い方を解説していきましょう。
通常のCData Salesforce Driverを使ったレコードの作成方法
CData Driverで一括リクエストを活用したレコードの作成を行うには、専用の文法があります。
通常通り一つ一つINSERT文などを発行しても、リクエストはバラバラになるだけなので注意しましょう。
まずひとつ目の方法ですが、以下のようにINSERT文のVALUESで複数の値を指定する方法です。通常のRDB操作でもお馴染みですね。
INSERT INTO Account(Name)VALUES('Hello'),('World');
もう一つはTEMPテーブルという、内部での疑似テーブルに一度格納して、最終的にINSERT INTO SELECT文でリクエストするという方法です。
INSERT INTO Account#TEMP (Name) VALUES ('Hello'); INSERT INTO Account#TEMP (Name) VALUES ('World'); INSERT INTO Account (Name) SELECT Name FROM Account#TEMP;
ちなみに、JDBCではバッチ処理専用のPreparedStatementがあり、これも内部的には同じように処理されます。ADOなどそれぞれのテクノロジーでも、専用の構文があるので、それぞれのリファレンスを参考にしてみてください。
String query = "INSERT INTO Account (Name) VALUES(?)"; PreparedStatement pstmt = conn.prepareStatement(query,Statement.RETURN_GENERATED_KEYS); pstmt.setString(1, "Jon Doe"); pstmt.addBatch(); pstmt.setString(1, "John"); pstmt.addBatch(); int[] r = pstmt.executeBatch(); for(int i: r) System.out.println(i); ResultSet rs = pstmt.getGeneratedKeys(); while(rs.next()){ System.out.println(rs.getString("Id")); }
その他、UPDATEやDELETEも同じアプローチで利用できます。詳しくは以下のリファレンスを参照してみてください。
内部の挙動・利用しているAPIについて
それでは続いて内部の挙動について確認しておきましょう。
この一括処理ですが、デフォルトではSOAP API の Createメソッド(もしくは、UpdateやDelete)を利用するようになっています。
例えば最初に紹介した以下のようなINSERT文ですが
INSERT INTO Account(Name)VALUES('Hello'),('World');
これをリクエストすることで最終的には以下のようなSOAP APIのリクエストが行われます。Objectsが2種類存在し、一度のリクエストに含まれていることがわかりますね。
対象となる値が増えると、このObjectsも追加され、一括でリクエストされるレコードが増え、効率的にデータの登録や更新を行うことができます。
<?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns="urn:enterprise.soap.sforce.com"> <Header> <SessionHeader xmlns="urn:enterprise.soap.sforce.com"> <sessionId> XXXXX </sessionId> </SessionHeader> </Header> <Body> <create xmlns="urn:enterprise.soap.sforce.com"> <sObjects xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns:Account" xmlns:ns="urn:sobject.enterprise.soap.sforce.com"> <Name> Hello </Name> </sObjects> <sObjects xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns:Account" xmlns:ns="urn:sobject.enterprise.soap.sforce.com"> <Name> World </Name> </sObjects> </create> </Body> </Envelope>
ちなみに、このAPIが利用される場合に注意するべきポイントは2つあります。
一つは一回にリクエストできる最大レコード数です。
リファレンスを確認する限りどのメソッドも最大200レコードまでリクエストをサポートしており、それを超えると操作全体が失敗するようになっています。
最大作成レコード数
クライアントアプリケーションは、1 回の create() コールで最大 200 個のレコードを追加できます。create 要求が 200 レコードを超えると、操作全体が失敗します。
しかしながら、CData Driverで一気に200レコード以上をTEMPテーブルに格納してリクエストしても、失敗することはありません。
これは、CData DriverがAPIリクエストを200レコード単位で分割してリクエストしてくれるからです。
もう一つ注意するべきは、エラー時のロールバック処理です。
通常は個別のレコードのロールバックはAPIの性質上行われません。しかしながら、AllOrNoneHeader を使用することで、ロールバックを行うことができるようになっています。
エラー時のロールバック
AllOrNoneHeader ヘッダーを使用すると、すべてのレコードが正常に処理されない限り、すべての変更をロールバックできます。このヘッダーは、API バージョン 20.0 以降で使用できます。正常に処理されないレコードがあった場合に、コールですべての変更をロールバックできます。
これは以下の「All Or None」接続プロパティをTrueにすることで利用できます。
CData Driverに限らず、ライブラリ系全般に言えることですが、内部で使われているAPIの仕様を知っておくと、「なぜこんなにAPIリクエストを消費しているのだろう?」などと思った際に切り分けがしやすいのでおすすめです。
ちなみに、CData Driver がどのようにAPIリクエストを行っているのか?についてはログを出力することが確認できます。
おわりに
というわけで、今回はSalesforce Driverを扱う上で、Tipsのような記事をお送りしました。
ちなみに、一回でより多くのレコードをリクエストしたい場合、Bulk APIのオプションを設定することが可能です。
Bulk APIを利用した場合のケースについては別な記事で紹介したいと思いますが、こちらも利用するシーンが多い機能ですので、一括処理を行いたい場合は是非試してみてください。