本文的上下文环境

操作系统:Win7 x64 Professional

开发工具:Visual Studio 2017   语言:C#

数据库ORM:IBatisNet 1.6.2

一、前言

这个项目的前端有Web端,公众号,微信小程序,后端是用WCF写的,部署成windows service。后端使用了IBatisNet这样的轻量级ORM框架,sql是写在xml里面的,每个模块都有一个xml文件。sql的返回值对应的实体类配置在同一个xml文件里,像这样。

一次寻找IBatisNet事务bug的过程

二、问题出现

 这个项目一直运行的很正常,直到有一天发布了某一个功能之后,问题就出现了,异常日志经常看到这样的文字“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();
            }
        }
    }
AopTransactionMethodAttribute

相关文章: