本文的上下文环境
操作系统:Win7 x64 Professional
开发工具:Visual Studio 2017 语言:C#
数据库ORM:IBatisNet 1.6.2
一、前言
这个项目的前端有Web端,公众号,微信小程序,后端是用WCF写的,部署成windows service。后端使用了IBatisNet这样的轻量级ORM框架,sql是写在xml里面的,每个模块都有一个xml文件。sql的返回值对应的实体类配置在同一个xml文件里,像这样。
二、问题出现
这个项目一直运行的很正常,直到有一天发布了某一个功能之后,问题就出现了,异常日志经常看到这样的文字“SqlMap could not invoke BeginTransaction(). A Transaction is already started. Call CommitTransaction() or RollbackTransaction first”,一看代码,这个异常是从SqlMapper.BeginTransaction方法里面抛出的,字面意思就是启动事务,不能正常启动,需要首先调用提交或回滚事务。按着这个逻辑来说,应该是某一次事务忘记提交或回滚了。但是这个错误在本地开发环境复现不了,线上环境时不时的出现。如果本地能够reproduce,应该会比较好解决一些。
三、查看bug起因
我们项目中事务用了PostSharp里面的AOP编程,只要在需要事务的方法上面加个attribute就能实现事务支持。代码如下:
[Serializable]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class AopTransactionMethodAttribute : MethodInterceptionAspect
{
//调用本函数时截取异常
public override void OnInvoke(MethodInterceptionArgs args)
{
Mapper.Instance().BeginTransaction();
try
{
//执行方法
base.OnInvoke(args);
}
catch
{
Mapper.Instance().RollBackTransaction();
throw;
}
TData result = args.ReturnValue as TData;
if (result == null || result.Tag <= 0)
{
//回滚事务
Mapper.Instance().RollBackTransaction();
}
else
{
//提交事务
Mapper.Instance().CommitTransaction();
}
}
}