我需要从外部数据源向我的数据库执行数据导入。由于需要下载大量数据,因此导入执行的时间很长,我需要将有关当前导入状态的定期更新保存到数据库(供用户使用)。交易操作同时与非交易操作混合
假设我有两个表:Import
(存储导入数据)和Status
(导入状态监视表)。
数据导入代码:
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
表连接的逻辑。
如何保留一致的导入并允许定期状态更新?
这【答案】(http://stackoverflow.com/a/2886326/1402923)在TransactionScope的行为可能是有用的。 – RobH