有时候我们的业务逻辑可能涉及多个数据库操作,如下代码片段所示,执行方法Option时,具体执行了3个对应的数据库操作方法,如果Option1执行成功,Option2失败,不采用事务的情况,Option1的结果会影响到数据库,Option2的结果不会影响数据库,这样会出现数据不一致的问题,在针对Option方法增加了事务的情况下,所有的数据库操作,要么全部成功,要么全部失败:
public bool Option1()
{
数据库操作1...
}
public bool Option2()
{
数据库操作2...
}
public bool Option3()
{
数据库操作3...
}
public bool Option()
{
this.Option1();
this.Option2();
this.Option3();
...
}
事务的具体实现主要使用了TransactionScope类,具体介绍可参考官方文档:使用事务范围实现隐式事务 - .NET Framework | Microsoft Docs
下面介绍如何在Asp.NET MVC项目中支持Action方法的事务功能。
1、项目中引入程序集System.Transactions
2、实现过滤器,定义自己的事务功能,用于拦截Action,注入事务功能。
/// <summary>
/// 事务拦截器,在action方法上增加该特性,可以自动增加事务功能,主要是利用了TransactionScope这个神器类
/// </summary>
public class TransactionScopeAttribute: ActionFilterAttribute
{
public TransactionScopeAttribute()
{
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
using (var txScope = new TransactionScope(TransactionScopeOption.Required))
{
try
{
//这里需要手动调用action方法,并且将执行结果赋值给filterContext,并且 return,否则该方法执行完后,目标action方法会重复执行
var result = filterContext.ActionDescriptor.Execute(filterContext.Controller.ControllerContext, filterContext.ActionParameters);
txScope.Complete();
filterContext.Result = (ContentResult)result;
return;
}
catch (Exception e)
{
throw e;
}
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}
}
3、在需要支持事务功能的action方法上增加特性TransactionScopeAttribute
/// <summary>
/// 批准操作
/// </summary>
/// <param name="keyValue">主键</param>
/// <returns></returns>
[TransactionScopeAttribute()]
public ActionResult PassAuthorizor(string keyValue, MES_ReleaseEntity entity)
{
if (string.IsNullOrEmpty(keyValue))
{
return Error($"传递参数keyValue不能为空!");
}
var rst = mes_releasebll.PassAuthorizor(keyValue, entity);
if (rst)
return Success("处理成功");
else
return Error("处理失败!");
}