Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (日本語) » Mobile Link - クライアント管理 » Mobile Link 用 SQL Anywhere クライアント » スクリプト化されたアップロード

 

スクリプト化されたアップロードの設計上の考慮事項

1 ローあたり 1 つの操作

アップロードには、1 つのローに対して複数の操作 (挿入、更新、または削除) を含めることはできません。ただし、複数の操作を 1 つのアップロード操作にまとめることはできます。たとえば、ローを挿入してから更新する場合は、2 つの操作を、最後の値を 1 回挿入する操作に置き換えることができます。

操作の順序

アップロードを統合データベースに適用すると、挿入と更新操作の後に削除操作が適用されます。特定のテーブル内での操作順序について他の想定をすることはできません。

競合の解決

同期と同期の間に複数のデータベースでローが更新されると、競合が発生します。アップロード内の各更新操作には、更新中のローの更新前イメージが含まれているので、Mobile Link サーバは競合を検出することができます。更新前イメージは、最後にアップロードまたはダウンロードに成功したローの全カラムの値です。アップロードが提供されたときに、更新前イメージが統合データベースの値と一致しないと、Mobile Link サーバは競合を検出します。

アプリケーションで競合を検出する必要があり、スクリプト化されたアップロードを使用している場合は、リモート・データベースで、最後にアップロードまたはダウンロードに成功した各ローの値を追跡する必要があります。これにより、正しい更新前イメージをアップロードできます。

更新前イメージのデータを維持する 1 つの方法は、同期テーブルと同一の更新前イメージ・テーブルを作成することです。次に、更新を実行するたびに更新前イメージ・テーブルを移植するトリガを同期テーブルに作成します。アップロードに成功したら、更新前イメージ・テーブルのローを削除できます。

競合解決の実装の例については、スクリプト化されたアップロードの例を参照してください。

競合を処理しない

競合の検出を処理する必要がない場合は、更新前イメージを追跡しなければ、アプリケーションを大幅に簡素化できます。代わりに、挿入操作として更新をアップロードします。次に、ローが存在しない場合は挿入し、存在する場合はローを更新する upload_insert スクリプトを統合データベースに作成します。SQL Anywhere 統合データベースを使用している場合、この操作は、upload_insert スクリプトの INSERT 文にある ON EXISTING 句を使用して実行できます。

INSERT 文を参照してください。

競合を処理せず、複数のリモート・データベースで同じローが変更されると、最後に同期したリモート・データベースによって、それまでの変更が上書きされます。

強制的な競合解決の処理

削除操作では、アップロードされたローのプライマリ・キーが正しいことが重要です。しかし、ほとんどの場合、非プライマリ・キー・カラムの値が、統合データベースの値と一致しているかどうかは問題ではありません。非プライマリ・キー・カラムが重要なのは、Mobile Link サーバで強制的な競合モードが使用されるときだけです。この場合、カラムのすべての値が、統合データベースの upload_old_row_insert スクリプトに渡されます。このスクリプトを実装した方法によっては、非プライマリ・キー・カラムを正しい値にする必要があります。

強制的な競合解決を参照してください。

ロッキング

スクリプト化されたアップロードの多くの問題は、dbmlsync 拡張オプション LockTables にデフォルト設定を使用することで防ぐことができます。この設定により、dbmlsync は、すべての同期テーブルの排他ロックを取得してから、アップロードを構築できます。これにより、スクリプトがアップロードを構築中に、他の接続が同期テーブルを変更するのを防ぐことができます。また、この設定を行うと、スクリプトがアップロードを構築中に、同期テーブルに影響するコミットされていないトランザクションをなくすことができます。

テーブルのロックをオフにする必要がある場合は、テーブルをロックしない場合のスクリプト化されたアップロードを参照してください。

冗長なアップロード

多くの場合、リモート・データベースで各操作をアップロードするのは、一度だけです。この操作を支援するため、Mobile Link は各サブスクリプションの進行状況値を維持します。進行状況値は、デフォルトで、dbmlsync が正常な最終アップロードを構築し始めた時間です。この進行状況値は、sp_hook_dbmlsync_set_upload_end_progress フックを使用して異なる値で上書きできます。

sp_hook_dbmlsync_set_upload_end_progressを参照してください。

アップロード・プロシージャの 1 つが呼び出されるたびに、#hook_dict テーブルを介して値が渡されます。渡される値としては、'start progress' や 'end progress' があります。これらの値は、リモート・データベースへの変更が構築中のアップロードに含まれるようにする時間を定義します。'start progress' 前に発生した操作は、すでにアップロードされています。'end progress' 後に発生する操作は、次の同期中にアップロードされます。

不明なアップロード・ステータス

スクリプト化されたアップロードの実装でよくある間違いは、sp_hook_dbmlsync_upload_end または sp_hook_dbmlsync_end フックを使用して、アップロードが正常に統合データベースに適用されたかどうだけを通知できるストアド・プロシージャを作成してしまうことです。この方法は信頼性に欠けます。

たとえば、次の例では、各ローの 1 ビットを使用して挿入を処理し、ローをアップロードする必要があるかどうかを追跡しようとしています。ビットは、ローが挿入されると設定され、アップロードが正常にコミットされると sp_hook_dbmlsync_upload_end フックで解除されます。

//
// DO NOT DO THIS!
//
CREATE TABLE t1 (
   pk    integer primary key,
   val      varchar( 256 ),
   to_upload   bit DEFAULT 1
);

CREATE PROCEDURE t1_ins()
RESULT( pk integer, val varchar(256) )
BEGIN
    SELECT pk, val
    FROM t1
    WHERE to_upload = 1;
END; 

CREATE PROCEDURE sp_hook_dbmlsync_upload_end()
BEGIN
    DECLARE     upload_status   varchar(256);

    SELECT value
    INTO upload_status
    FROM #hook_dict
    WHERE name = 'upload status';

    if upload_status = 'committed' THEN
        UPDATE t1 SET to_upload = 0;
    END IF
END;

      CREATE PUBLICATION p1 WITH SCRIPTED UPLOAD (
           TABLE t1 USING ( PROCEDURE t1_ins FOR UPLOAD INSERT )
      );

この方法は、ほとんどの場合に機能します。ハードウェアまたはソフトウェアの障害が発生し、アップロードが送信された後、サーバで受信確認される前に、dbmlsync が停止されると、失敗します。この場合、アップロードは統合データベースに適用されますが、sp_hook_dbmlsync_upload_end フックは呼び出されず、to_upload ビットは解除されません。その結果、次回の同期では、アップロード済みのローに挿入がアップロードされます。この場合、通常は統合データベースで重複プライマリ・キー・エラーが発生し、同期が失敗します。

そのほかには、Mobile Link サーバとの通信が、アップロードが送信された後、受信確認される前に失われた場合に、問題が発生します。この場合、dbmlsync は、アップロードが正常に適用されたかどうかを確認できません。dbmlsync は sp_hook_dbmlsync_upload_end フックを呼び出して、アップロード・ステータスを不明に設定します。フックが作成されると、to_upload ビットが解除されるのを防ぐことができます。サーバによってアップロードが適用されなかった場合、問題は発生しません。ただし、アップロードが適用されると、前述と同じ問題が発生します。いずれの場合も、問題を手動で解決するまで、影響を受けたリモート・データベースを再び同期することはできません。

ダウンロード時のデータ損失の防止

スクリプト化されたアップロードを使用すると、リモート・データベースでアップロードが必要なデータが、統合データベースからダウンロードされたデータで上書きされる可能性があります。この場合、リモート・データベースでの変更内容が失われます。アップロード・プロシージャで構築するアップロードに、sp_hook_dbmlsync_set_upload_end_progress hook フックの呼び出し前にリモート・データベースでコミットされた変更内容がすべて含まれる場合は、dbmlsync によってデータ損失が防止されます。

この規則に従わなかった場合にデータがどのように失われるかを次の例に示します。

時間
1:05:00 統合データベースとリモート・データベースの両方にあるロー R が、リモート・データベースで新しい値 R1 に更新され、変更がコミットされます。
1:06:00 統合データベースでロー R が新しい値 R2 に更新され、変更がコミットされます。
1:07:00 同期が発生します。アップロード・スクリプトは、1:00:00 より前にコミットされた操作だけが含まれるように記述されています。アップロードの構築前に発生したすべての操作がアップロードされないので、これは規則に従っていません。ロー R への変更は、1:00:00 を過ぎてから発生したのでアップロードに含まれません。サーバから受信されるダウンロードにはロー R2 が含まれます。ダウンロードが適用されると、リモート・データベースのロー R1 がロー R2 に置き換わります。リモート・データベースでの更新内容は失われます。

dbmlsync は、複数のメカニズムを使用して、sp_hook_dbmlsync_set_upload_end_progress フックの呼び出し時にコミットされていなかった変更または sp_hook_dbmlsync_set_upload_end_progress フックの呼び出し後にコミットされた変更がダウンロード内容で上書きされないようになっています。

フックの呼び出し前にコミットされた変更は保護されないので、ダウンロードの適用時に上書きが可能です。ただし、ダウンロード構築前に送信されるアップロードに変更内容が含まれれば、変更内容は Mobile Link サーバに送信されるので、サーバ側のスクリプトで、統合データベース内のデータとの間で競合を解決してから、ダウンロードを構築できます。


テーブルをロックしない場合のスクリプト化されたアップロード