使用Asp.Net MVC进行自动交易的最佳方法是什么?

时间:2022-08-26 20:49:05

I'm getting annoyed with writing the following code all over the place in my MVC app.

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

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

I'd like to make this DRYer somehow.

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

I've thought of a couple different options for this.

我想到了几个不同的选择。

  1. An action filter to declaratively mark certain actions as transactional.
  2. 一个动作过滤器,以声明方式将某些操作标记为事务性操作。

  3. Override OnActionExecuting in a Controller base class and make all actions transactional in one shot.
  4. 覆盖Controller基类中的OnActionExecuting并一次性处理所有操作事务。

Are either of these a good idea? Any gotcha's I should look out for? The 2nd option seems like it might be a good way to get lots of deadlocks.

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

Oh yeah, I'm also using StructureMap and a custom controller factory to inject deps into my controllers in case someone knows of some tricks for injecting transactions that way.

哦,是的,我也在使用StructureMap和一个自定义控制器工厂将deps注入我的控制器,以防有人知道一些注入事务的技巧。

2 个解决方案

#1


You can use the Unit of Work pattern to do your transaction management. The major benefit of the unit of work pattern is that you can keep your transaction strategy on one place, or a few places when you have multiple strategies. The most simple unit of work interface could be:

您可以使用工作单元模式进行事务管理。工作单元模式的主要好处是,当您有多个策略时,您可以将交易策略保留在一个地方或几个地方。最简单的工作单元界面可以是:

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

You can create various UnitOfWork implementations for different ORMs or for stored procedures or on hard-coded sql. You can start the transaction in the begin of the request. The transaction can be disposed on the end of the request. Before the disposal, you can wrap the commit in a try-catch block with rollback in the catch.

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

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

There transaction start strategies are:

交易启动策略是:

  • Per request: one transaction is used on the whole request, this is the best way in most cases.
  • 每个请求:在整个请求中使用一个事务,这是大多数情况下的最佳方法。

  • Multiple times per request: A transaction per method.
  • 每个请求多次:每个方法的事务。

  • Per Conversation: You can create a transaction around several requests of a shopping cart checkout process.
  • 每次对话:您可以围绕购物车结帐流程的多个请求创建一个交易。

You can manage your transaction with:

您可以使用以下方式管理交易:

  • attributes
  • application_begin and endrequest method in global.asax
  • global.asax中的application_begin和endrequest方法

  • httpmodule

When using StructureMap, you can use Hybrid caching as InstanceScope in the unit of work configuration. You can inject the unit of work into repositories with StructureMap.

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

#2


In an application I am currently developing, my repositories get an NHibernate ISession from an ISessionProvider which is injected in the constructor. The session provider is an AspNetMvcSessionProvider, which will create an ISession and begin a transaction the first time ISessionProvider.OpenSession() is called, storing the ISession in the current web request.

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

In OnActionExecuted I manually pull the ISessionProvider out of my container and call Commit or RollBack on it, depending on whether an exception has been thrown - doing nothing of course, if no session is currently stored in the web request.

在OnActionExecuted中,我手动将ISessionProvider拉出我的容器并在其上调用Commit或RollBack,具体取决于是否抛出异常 - 当然,如果Web请求中当前没有存储会话,则不执行任何操作。

This has proven useful and I think it performs pretty well - most of the time, the application is merely reading data, which does not block other reading transactions. I have not yet experienced a database deadlock.

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

#1


You can use the Unit of Work pattern to do your transaction management. The major benefit of the unit of work pattern is that you can keep your transaction strategy on one place, or a few places when you have multiple strategies. The most simple unit of work interface could be:

您可以使用工作单元模式进行事务管理。工作单元模式的主要好处是,当您有多个策略时,您可以将交易策略保留在一个地方或几个地方。最简单的工作单元界面可以是:

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

You can create various UnitOfWork implementations for different ORMs or for stored procedures or on hard-coded sql. You can start the transaction in the begin of the request. The transaction can be disposed on the end of the request. Before the disposal, you can wrap the commit in a try-catch block with rollback in the catch.

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

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

There transaction start strategies are:

交易启动策略是:

  • Per request: one transaction is used on the whole request, this is the best way in most cases.
  • 每个请求:在整个请求中使用一个事务,这是大多数情况下的最佳方法。

  • Multiple times per request: A transaction per method.
  • 每个请求多次:每个方法的事务。

  • Per Conversation: You can create a transaction around several requests of a shopping cart checkout process.
  • 每次对话:您可以围绕购物车结帐流程的多个请求创建一个交易。

You can manage your transaction with:

您可以使用以下方式管理交易:

  • attributes
  • application_begin and endrequest method in global.asax
  • global.asax中的application_begin和endrequest方法

  • httpmodule

When using StructureMap, you can use Hybrid caching as InstanceScope in the unit of work configuration. You can inject the unit of work into repositories with StructureMap.

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

#2


In an application I am currently developing, my repositories get an NHibernate ISession from an ISessionProvider which is injected in the constructor. The session provider is an AspNetMvcSessionProvider, which will create an ISession and begin a transaction the first time ISessionProvider.OpenSession() is called, storing the ISession in the current web request.

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

In OnActionExecuted I manually pull the ISessionProvider out of my container and call Commit or RollBack on it, depending on whether an exception has been thrown - doing nothing of course, if no session is currently stored in the web request.

在OnActionExecuted中,我手动将ISessionProvider拉出我的容器并在其上调用Commit或RollBack,具体取决于是否抛出异常 - 当然,如果Web请求中当前没有存储会话,则不执行任何操作。

This has proven useful and I think it performs pretty well - most of the time, the application is merely reading data, which does not block other reading transactions. I have not yet experienced a database deadlock.

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