我的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 @ 2015-05-26 14:14  NewSea  阅读(1640)  评论(0编辑  收藏  举报