我的ORM之五-- 事务

我的ORM索引

单库事务与分布式事务

单库事务: 性能更好,应用于一个数据库时的场景,当数据库发生变化,如拆分为多个服务器,代码需要修改。

分布式事务:性能相对较差,但有更大的适用场景。当数据库发生变化,如拆分为多个服务器,代码可能不需要修改。

由于事务会引起资源争抢,互联网平台,越来越趋向无事务处理,追求极致的性能。

分布式事务

复制代码
using (ransactionScope scope = new TransactionScope())

     {

        //to do something

        scope.Complete();

     }
复制代码

 

单库事务

在实际应用中,我更倾向于单库事务。用法也很像分布式事务,可以嵌套。

复制代码
string errorMsg = dbr.表1.ExecTransaction(()=>

{

  if( 表1操作失败) return "表1失败";

  if( 表2操作失败) return "表2失败";

  if( 表3操作失败) return "表3失败";

 

     var msg = 调用其它单库事务方法;

  if( msg.HasValue() )  return msg;

 

     return "";

});
复制代码

 

在 ExecTransaction 方法中,返回空值或空字符串,表示成功。 如果返回错误信息,则事务回滚。

具体实现方法:(需根据项目修改)

实现思想:在执行事务前,先使用 lock 锁住某个表示该表的对象。使其它使用该表的事务在数据库外排队,防止死锁。

复制代码
public static string ExecTransaction(this RuleBase rule, Func<string> func)
{
    return ExecTransaction(rule, new LockObjectEnum(), func);
}

/// <summary>
/// 单库事务安全执行方法
/// </summary>
/// <param name="rule"></param>
/// <param name="func"></param>
/// <returns></returns>
public static string ExecTransaction(this RuleBase rule, LockObjectEnum LockObj, Func<string> func)
{
    var group = rule.GetGroupName().AsString(me.CorpID.ToString());

    if (LockObj.HasValue() == false)
    {
        group.MySplit('_').All(g =>
        {
            var e = g.ToEnum<LockObjectEnum>();
            if (e > 0)
            {
                LockObj = e;
                return false;
            }
            return true;
        });
    }

    var ret = string.Empty;

    lock (rule.GetLockObject())
    {
        For2Recusion(LockObj.GetEnumList(), () =>
        {
            ret = _execTransactionWithoutLock(rule, func);
        });
    }

    return ret;
}

private static void For2Recusion(LockObjectEnum[] objs, Action act, int index = 0)
{
    if (index < objs.Length)
    {
        lock (MyHelper.GetLockObject("ExecTransaction." + objs[index].ToString()))
        {
            For2Recusion(objs, act, index + 1);
        }
    }
    else
    {
        act();
    }
}


private static string _execTransactionWithoutLock(RuleBase rule, Func<string> func)
{
    var msg = string.Empty;
    if (dbo.CurrentScope != null && dbo.CurrentScope.Transaction != null)
    {
        try
        {
            msg = func();

            if (msg.HasValue())
            {
                return msg;
            }
        }
        catch (Exception e)
        {
            msg = e.Message;
            throw;
        }
        return msg;
    }
    using (var conn = rule.GetDbConnection())
    {
        msg = dbo.Open(conn, () =>
        {
            var tran = conn.BeginTransaction();
            using (var scope = new MyOqlConfigScope(tran))
            {
                try
                {
                    msg = func();

                    if (msg.HasValue())
                    {
                        tran.Rollback();
                        return msg;
                    }

                    tran.Commit();
                }
                catch (Exception e)
                {
                    msg = e.Message;

                    if (conn.State != ConnectionState.Closed)
                    {
                        tran.Rollback();
                    }

                    throw;
                }
                return msg;
            }
        });
    }
    return msg;
}
复制代码

 

posted @   NewSea  阅读(1646)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示