我对使用事务RDBMS非常熟悉,但是如果事务失败,我如何确保对内存数据所做的更改被回滚?如果我甚至不使用数据库怎么办?
这是一个人为的例子:
public void TransactionalMethod()
{
var items = GetListOfItems();
foreach (var item in items)
{
MethodThatMayThrowException(item);
item.Processed = true;
}
}
Run Code Online (Sandbox Code Playgroud)
在我的示例中,我可能希望以某种方式回滚对列表中项目所做的更改,但是如何实现此目的呢?
我知道"软件事务存储器",但对它不太了解,看起来相当实验性.我也知道"可补偿交易"的概念,但这会产生编写执行/撤消代码的开销.
Subversion似乎通过让你运行"cleanup"命令来处理更新工作副本的错误.
有任何想法吗?
更新:
Reed Copsey提供了一个很好的答案,包括:
处理数据副本,在提交时更新原始数据.
这使我的问题更进一步 - 如果在提交期间发生错误怎么办?我们经常将提交视为即时操作,但实际上它可能会对大量数据进行许多更改.如果OutOfMemoryException在应用提交时存在不可避免的事情,会发生什么?
另一方面,如果有人选择回滚选项,如果在回滚期间出现异常会发生什么?我理解像Oracle RDBMS这样的东西有回滚段和UNDO日志和东西的概念,但假设没有序列化到磁盘(如果没有序列化到磁盘,它没有发生,崩溃意味着你可以调查那些日志并从中恢复),这真的可能吗?
更新2:
一个答案从亚历克斯做了一个很好的建议:即一个更新不同的对象,然后,提交阶段只不过是修改过的新对象的引用到当前对象.他进一步建议你改变的对象实际上是修改对象的列表.
我明白他在说什么(我想),我想让问题更复杂:
在这种情况下,你如何处理锁定?想象一下,你有一个客户列表:
var customers = new Dictionary<CustomerKey, Customer>();
Run Code Online (Sandbox Code Playgroud)
现在,您想要对其中一些客户进行更改,如何在不锁定和替换整个列表的情况下应用这些更改?例如:
var customerTx = new Dictionary<CustomerKey, Customer>();
foreach (var customer in customers.Values)
{
var updatedCust = customer.Clone();
customerTx.Add(GetKey(updatedCust), updatedCust);
if (CalculateRevenueMightThrowException(customer) >= 10000)
{
updatedCust.Preferred = true;
}
}
Run Code Online (Sandbox Code Playgroud)
我该怎么做?这(Alex的建议)将意味着在替换列表引用时锁定所有客户:
lock (customers)
{
customers = customerTx;
}
Run Code Online (Sandbox Code Playgroud)
然而,如果我循环,修改原始列表中的引用,它不是原子的,并且与"如果它在中途崩溃的问题"中的问题相违背:
foreach (var kvp in customerTx)
{
customers[kvp.Key] = kvp.Value;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
774 次 |
| 最近记录: |