外部ソースからデータベースへのデータ インポートを実行する必要があります。ダウンロードするデータが多いため、インポートは長時間実行され、現在のインポート状態に関する定期的な更新をデータベースに保持する必要があります (ユーザーがフォローできるようにするため)。
Import
(インポートされたデータのストレージ) とStatus
(状態監視テーブルのインポート) の2 つのテーブルがあるとします。
データ インポートのコード:
public class Importer
{
public delegate void ImportHandler(string item);
public event ImportHandler ImportStarted;
public void OnStart(string item)
{
ImportStarted(item);
}
public void Execute(string[] items)
{
foreach (var item in items)
{
OnStart(item);
PersistImportedData(Download(item));
}
}
private void PersistImportedData(object data)
{
using (var connection = new SqlConnection()){ /*saving imported data*/ }
}
}
スターター コード - インポート タスクを呼び出し、そのステータスを更新するためのコード:
public class Starter
{
public void Process(string[] items)
{
var importer = new Importer();
importer.ImportStarted += UpdateImportState;
importer.Execute(items);
}
private void UpdateImportState(string item)
{
using (var connection = new SqlConnection()){ /*status updates*/ }
}
}
今、すべてが正常に動作します。インポートが実行されており、ユーザーはStatus
インポートが進行するにつれて (テーブルから) ステータスの更新を取得しています。
この問題は、そのようなロジックが安全でないために発生します。インポートはアトミック操作であることを確認する必要があります。部分的にダウンロードして保存したデータは必要ありません。私はこれに対する解決策としてトランザクションアプローチを使用しました (私は でラップimporter.Execute
しましたTransactionScope
):
importer.ImportStarted += UpdateImportState;
using (var scope = new TransactionScope())
{
importer.Execute(items);
scope.Complete();
}
これで安全になりました。たとえば、プロセスが中止された場合にロールバックが発生します。
私は今別の問題に直面しました - 私が解決したい問題です。ユーザーが表示するステータス更新情報が必要ですが、Status
テーブルは更新の影響を受けず、トランザクションはまだ完了していません。RequiresNew
別のトランザクション (アンビエント トランザクションではない) を作成するオプションを使用しようとしても、何も変わりません。このExecute
関数は、データベースへの独自の接続を作成UpdateImportState
し、同じことを行います。接続は共有されません。テーブルに接続されたロジックのみをカバーしているのにState
、なぜテーブルが影響を受けないのかわかりません。TransactionScope
Import
一貫したインポートを維持し、定期的なステータス更新を許可する方法は?