3

我对在我的 MVC 应用程序中到处编写以下代码感到恼火。

using(var tx = new TransactionScope()){
   blah...
   tx.Complete()
}

我想以某种方式制作这款 DRYer。

我为此想到了几种不同的选择。

  1. 一个动作过滤器,以声明方式将某些动作标记为事务性的。
  2. 重写 Controller 基类中的 OnActionExecuting 并一次性使所有操作都具有事务性。

这些都是一个好主意吗?有什么我应该注意的问题吗?第二个选项似乎可能是获得大量死锁的好方法。

哦,是的,我还使用 StructureMap 和自定义控制器工厂将 deps 注入到我的控制器中,以防有人知道以这种方式注入事务的一些技巧。

4

2 回答 2

2

您可以使用工作单元模式来进行事务管理。工作单元模式的主要好处是您可以将事务策略保存在一个地方,或者当您有多个策略时,可以将其保存在几个地方。最简单的工作单元接口可能是:

public interface IUnitOfWork
{
    void Start();
    void Commit();
    void RollBack();
}

您可以为不同的 ORM 或存储过程或硬编码的 sql 创建各种 UnitOfWork 实现。您可以在请求开始时启动事务。事务可以在请求结束时处理。在处理之前,您可以将提交包装在 try-catch 块中,并在 catch 中回滚。

try
{
    unitOfWork.Commit();
} 
catch
{
     unitOfWork.RollBack();
     throw;
}

事务启动策略有:

  • 每个请求:一个事务用于整个请求,这是大多数情况下的最佳方式。
  • 每个请求多次:每个方法一个事务。
  • 每个对话:您可以围绕购物车结账过程的多个请求创建交易。

您可以通过以下方式管理您的交易:

  • 属性
  • global.asax 中的 application_begin 和 endrequest 方法
  • http模块

使用 StructureMap 时,您可以在工作单元配置中使用 Hybrid 缓存作为 InstanceScope。您可以使用 StructureMap 将工作单元注入到存储库中。

于 2009-04-17T21:59:43.673 回答
1

在我目前正在开发的一个应用程序中,我的存储库ISession从一个ISessionProvider注入到构造函数中的 NHibernate 中获取。会话提供者是 an AspNetMvcSessionProvider,它将创建一个ISession并在第一次ISessionProvider.OpenSession()调用时开始一个事务,将 存储ISession在当前的 Web 请求中。

OnActionExecuted我手动拉出ISessionProvider我的容器并调用Commit或调用RollBack它,具体取决于是否引发了异常 - 当然,如果 Web 请求中当前没有存储会话,则什么也不做。

这已被证明是有用的,而且我认为它表现得非常好——大多数时候,应用程序只是读取数据,不会阻塞其他读取事务。我还没有经历过数据库死锁。

于 2009-04-17T20:35:03.987 回答