用于在数据库之外实现事务的模式

时间:2009-02-24 03:09:12

标签: .net transactions acid

我必须发送电子邮件,写入文件,然后调用Web服务。为了保持一致性,必须执行所有步骤。如果任何步骤抛出异常或错误,则必须回滚所有步骤。

在我开始使用自己的对象ACID引擎之前,是否有在对象级别实现ACID语义的常用模式?

更好的是,我可以在.NET平台上使用任何现有的库吗?

编辑:我知道发送电子邮件无法撤消,但无法连接到SMTP服务器会导致终止整个事务。此外,我希望这可以扩展用于将来的行动。

7 个答案:

答案 0 :(得分:5)

几年前我最后一次看到这样的事情。我记得的一点是,它使用命令模式并将每个命令对象存储在队列中。我认为这是一个LIFO堆栈。

因此,如果“事务”失败,引擎将弹出命令对象,撤消命令,然后销毁命令对象。重复直到堆栈为空。如果“交易”成功,堆栈就会被清除。

不幸的是,我不记得更多。

CSLA.NET实现了类似的撤销堆栈。这是代码的唯一例子,我可以从头脑中思考。

答案 1 :(得分:3)

当ACID语义可能不合适时,Windows Workflow Foundation有一个概念compensation(使用Composite活动)。当然,它也支持ACID事务。

  

一个好问题是为什么要打扰   补偿?不是一个大的ACID   具有自动回滚的事务   一样好吗? ACID交易是   操作发生时最合适   在同一个数据库内或在   相同的信息系统。也是   操作结束时最合适   很快。当不同的公司和   涉及服务,定义   根据ACID语义进行处理   经常充满挑战。对于它   隔离和耐用,你必须保持   不同公司的所有资源   在任务期间锁定。   这通常是不合理的,   特别是如果任务很长。为了它   为了保持一致和原子,你需要   临时补偿代码。

答案 2 :(得分:3)

不依赖外部库的最简单技术是prevalence。定期 checkpoint 使用序列化来拍摄状态的快照,然后通过序列化有关数据的每个副作用操作的足够信息来维护日记,以便稍后重复。如果出现问题,请重新加载最新的检查点,然后重新应用该点之后写的所有日志记录。

对于更复杂的内容,请尝试software transactional memory。在当前语言中实现可能有些笨拙,但功能非常强大,并且可能会为您提供一些额外的并发技术。

对于访问Web服务或发送电子邮件等不可逆转的操作,您需要使用compensating transactions:拨打另一个Web服务来取消或更新上一个的结果,或者发送另一封电子邮件通知收件人认为事情没有按预期发挥作用。

答案 3 :(得分:1)

由于您无法取消发送电子邮件,并且编写文件相对便宜,我只是按照正确的顺序执行这些操作:

  1. 尝试编写文件/写入文件。如果不成功,请停止,否则继续:
  2. 调用Web服务。如果不成功,请删除该文件并停止,否则继续:
  3. 发送电子邮件 - 无论如何,电子邮件都是异步的,所以你永远都不知道它是否已发送,因为如果发生错误并且你永远不会得到错误,大多数电子邮件服务器会被设置为重试几天即使 成功,也要确认电子邮件已经通过。

答案 4 :(得分:1)

一个想法是使用JMS作为“引擎”,您可以利用JMS事务(可以加入现有事务,例如DB事务)。这开始导致异步事件驱动的体系结构,除非我们讨论简单的应用程序,否则这可能是一件好事 - 在这种情况下,您可能不需要提出问题。

这方面的一个例子是简单的帐户创建。为此,您希望将帐户信息保存到数据库,并向用户发送电子邮件以进行激活 - 但出于显而易见的原因,您希望将它们放在同一个事务中。

您不应该在交易中放置电子邮件发送代码,因为即使您可能发送电子邮件 - 数据库事务提交可能由于某种原因而失败。 您也不应该将电子邮件发送到交易之外(提交后),因为电子邮件发送可能会导致孤立帐户失败。

所以在这种情况下使用JMS - 让JMS在数据库事务中发送代码并让它加入该事务。保证邮件传递。在另一端有消耗队列发送电子邮件的东西。如果电子邮件发送失败,最好的选择是记录/发出警报 - JMS将回滚并将消息放回队列中供以后使用。即,一旦你有希望解决问题,尝试重新发送电子邮件。

关键是 - 数据库记录是一致的,最终会发送电子邮件。

答案 5 :(得分:0)

两个想法:

答案 6 :(得分:0)

此外,最近发布了一个实验项目STM .NET。这个项目为C#增加了事务内存。它实际上修改了CLR以支持这一点。