27
2017
08

ABP框架UnitOfWork事务使用注意事项

更新接口代码

/// <summary>
/// 更新库存量
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(isTransactional: false)]
public SaveStockOutput SaveStock(SaveStockInput input)
{
        using (var unitOfWork = _unitOfWorkManager.Begin())
        {
                ………………………………………………………………………………………………………………………………………………………………
                _preventDuplicationRealtimeRepository.InsertAndGetId(dupModel);//插入防重key
                _itemContractStockRepository.InsertAndGetId(itemContractStock);//插入库存数据
                …………………………………………………………………………………………………………………………………………………………………
                _unitOfWorkManager.Current.SaveChanges();
                unitOfWork.Complete();
        }
        ……………………………………………………………………………………………………………………………………………………………………………
}


线上库存是加了防重Key,最近经常出现防重key插入成功,库存没插入成功,就出问题了。

今天也是测试了一下

[UnitOfWork(isTransactional: false)]
public void Test()
{
    try
    {
        using (var unitOfWork = _unitOfWorkManager.Begin())
        {
            var dupModel1 = new PreventDuplicationRealtime()
            {
                CreatedDate = DateTime.Now,
                DupType = (int)PreventDuplicationDupType.SaveStock,
                DupKey = "00_02_01_test"
            };
            _preventDuplicationRealtimeRepository.InsertAndGetId(dupModel1);//事先不存在
            var dupModel = new PreventDuplicationRealtime()
            {
                CreatedDate = DateTime.Now,
                DupType = (int)PreventDuplicationDupType.SaveStock,
                DupKey = "00_00_01_test"
            };
            _preventDuplicationRealtimeRepository.InsertAndGetId(dupModel);//事先存在,插入报错
            _unitOfWorkManager.Current.SaveChanges();
            unitOfWork.Complete();
        }
    }
    catch (Abp.AbpException abpex)
    {
        var ex = abpex.GetOriginalException();
        if (!ex.IsNotCallCompleteException())//不是事务提交问题才重新抛出异常
        {
            throw new Exception("SaveStock报错:", abpex);
        }
    }
    catch (Exception dupEx)
    {
        var ex = dupEx.GetOriginalException();
        if (ex.Message.StartsWith("Duplicate", StringComparison.OrdinalIgnoreCase) && ex.Message.Contains("key"))
        {
            var t = "重复保存";
        }
        else throw dupEx;
    }
}


这个测试代码运行之后,00_02_01_test被写入数据库。而去掉isTransactional:false之后,00_02_01_test不会被写入,整个测试方法会作为一个事务执行。

 

于是就去官网查相关文档,这个isTransactional:false一直感觉不对劲,但一直这么用着觉得问题也不大。看到了文档才知道是误用了。



意思大概是说,如果isTransactional:false,那么直接执行sql的代码就不会回滚;还有使用isTransactional:false必须要小心,假如你的方法只读取数据,那么使用它就是安全的。言外之意就是,如果有修改数据,那么不应该使用isTransactional:false。

所以,以后使用ABP框架开发的话一定要注意这个问题。

 

文档地址:https://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work#DocUowNoTransaction

 

 

更新:2017-08-25

经测试及验证情况如下:

  1. 没有标记[UnitOfWork]属性,默认存在事务,内部事务并不会马上提交,当请求结束时才提交事务

  2. 标记[UnitOfWork(IsDisabled = true)] ,禁用了事务功能,仓储在using (var unitOfWork = _unitOfWorkManager.Begin()){}内部可以,外部可能因为连接关闭如出错。小心使用该属性

  3. 标记[UnitOfWork(isTransactional: false)],不使用事务,仓储内容会马上提交,包括使用using (var unitOfWork = _unitOfWorkManager.Begin()){}内部事务,并不会回滚

  4. 标记[UnitOfWork(isTransactional: false)],并使用using (var unitOfWork = _unitOfWorkManager.Begin(System.Transactions.TransactionScopeOption.RequiresNew)){},内部事务有效,能事务提交及回滚

所以使用内部事务,建议使用方案4

using (var unitOfWork = _unitOfWorkManager.Begin(System.Transactions.TransactionScopeOption.RequiresNew))
{
    switch (item.StockPattern)
    {
        case StockPattern.ItemContractStock:
            result = saveContractPriceInput.MsgFrom == UpdatePriceMsgFromType.Linkage ? SaveItemLinkageContractPrice(saveContractPriceInput, eventDataList) : SaveItemContractPrice(saveContractPriceInput, eventDataList);
            break;
        case StockPattern.ItemLimitedTimeStock:
            result = SaveItemLimitedTimeContractPrice(saveContractPriceInput, eventDataList);
            break;
        default:
            result = new SaveContractPriceOutput { Success = false, ErrorMessage = "未实现的元素库存类型" };
            break;
    }
    unitOfWork.Complete();
}

 


库存开发注意事项:

所有只查询数据不修改数据的service方法,都要加上 [UnitOfWork(isTransactional: false)] 标记以提高查询性能。因为默认查询也会加事务,如果查询时间过长会报事物中止或超时等等异常。




版权声明:
作者:真爱无限 出处:http://www.pukuimin.top 本文为博主原创文章版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.
« 上一篇下一篇 »

相关文章:

评论列表:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。