如何在内存中进行事务处理?

我对使用事务RDBMS非常熟悉,但是如果事务失败,我如何确保对内存中数据所做的更改被回滚? 如果我甚至不使用数据库怎么办?

这是一个人为的例子:

public void TransactionalMethod() { var items = GetListOfItems(); foreach (var item in items) { MethodThatMayThrowException(item); item.Processed = true; } } 

在我的示例中,我可能希望以某种方式回滚对列表中项目所做的更改,但是如何实现此目的呢?

我知道“软件事务记忆”,但对它知之甚少,似乎相当实验性。 我也知道“可补偿交易”的概念,但这会产生编写执行/撤销代码的开销。

Subversion似乎通过让你运行“cleanup”命令来处理更新工作副本的错误。

有任何想法吗?

更新:
Reed Copsey提供了一个很好的答案 ,包括:

处理数据副本,在提交时更新原始数据。

这使我的问题更进一步 – 如果在提交期间发生错误怎么办? 我们经常将提交视为即时操作,但实际上它可能会对大量数据进行许多更改。 如果在应用提交时存在不可避免的事情,例如OutOfMemoryException会发生什么?

另一方面,如果有人选择回滚选项,如果在回滚期间出现exception会发生什么? 我理解像Oracle RDBMS这样的东西有回滚段和UNDO日志和东西的概念,但假设没有序列化到磁盘(如果它没有序列化到磁盘,它没有发生,崩溃意味着你可以调查这些日志并从中恢复),这真的可能吗?

更新2:
Alex的回答提出了一个很好的建议:即更新一个不同的对象,然后,提交阶段只是将对当前对象的引用更改为新对象。 他进一步建议你改变的对象实际上是修改对象的列表。

我明白他在说什么(我想),我想让问题更复杂:

在这种情况下,你如何处理锁定? 想象一下,你有一个客户列表:

 var customers = new Dictionary(); 

现在,您想要对其中一些客户进行更改,如何在不锁定和替换整个列表的情况下应用这些更改? 例如:

 var customerTx = new Dictionary(); foreach (var customer in customers.Values) { var updatedCust = customer.Clone(); customerTx.Add(GetKey(updatedCust), updatedCust); if (CalculateRevenueMightThrowException(customer) >= 10000) { updatedCust.Preferred = true; } } 

我该怎么做? 这(Alex的建议)意味着在替换列表引用时锁定所有客户:

 lock (customers) { customers = customerTx; } 

然而,如果我循环,修改原始列表中的引用,它不是primefaces的,并且与“如果它在中途崩溃的问题”相违背:

 foreach (var kvp in customerTx) { customers[kvp.Key] = kvp.Value; } 

几乎所有这样做的选择都需要以下三种基本方法之一:

  1. 在修改之前复制数据,如果中止则恢复为回滚状态。
  2. 处理数据副本,在提交时更新原始数据。
  3. 记录您的数据更改,以便在中止时撤消它们。

例如,您提到的软件事务内存遵循第三种方法。 关于这一点的好处是它可以乐观地处理数据,并且只是在成功提交时丢弃日志。

看一下Microsoft Research项目SXM 。

从Maurice Herlihy的页面 ,您可以下载文档和代码示例。

您询问:

“如果在提交期间发生错误怎么办?”

没关系。 您可以提交到内存中的某个/某些内容,同时检查操作是否成功。 如果是,则将目标对象(对象A)的引用更改为您提交的对象(对象B)。 然后你有failafe提交 – 只有在成功提交时才会更新引用。 参考变化是primefaces的。

 public void TransactionalMethod() { var items = GetListOfItems(); try { foreach (var item in items) { MethodThatMayThrowException(item); item.Processed = true; } } catch(Exception ex) { foreach (var item in items) { if (item.Processed) { UndoProcessingForThisItem(item); } } } } 

显然,“撤销……”的实施仍然是读者的练习。