65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的自定义业务事务

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (3投票s)

2007年11月19日

2分钟阅读

viewsIcon

30209

downloadIcon

296

一篇基于 LLBLGen Pro 实现自定义业务事务类的文章。

引言

在每个项目中,我们都需要一个业务事务类来帮助我们控制业务流程。这个类应该能够处理嵌套事务。我编写了一个名为“BusinessTransaction”的类,并希望与所有在处理嵌套事务时遇到问题的人分享它。

背景

在许多情况下,我们有一些服务/门面/管理器,它们处理数据容器并将它们保存到数据库中。有时这些服务也会相互调用,在这种情况下,如果在内部服务中发生任何异常,则异常将在 2 层事务中抛出,并且两者都应该回滚。

例如,在像这样的算法中:

public void X() 
{     
   try    
   {    
      transaction.Start();         
      console.WriteLine("X");
      transaction.Commit();
    }     
    catch(Exception ex) 
    { 
        transaction.Rollback();        
        throw ex;    
    }
} 
public void Y() 
{     
   try    
   {    
      transaction.Start();
      console.WriteLine("Y");
      transaction.Commit();
    }     
    catch(Exception ex) 
    { 
        transaction.Rollback();        
        throw ex;    
    }
}  
public void Z() 
{     
   try    
   {    
      transaction.Start();         
      X();
      Y();
      transaction.Commit();
    }     
    catch(Exception ex) 
    { 
        transaction.Rollback();        
        throw ex;    
    }
} 

我们可能会遇到以下情况:

1- 异常发生在 X 事务之间:X 和 Z 应该回滚。

2- 异常发生在 X 提交之后且 Y 事务之间:X、Y 和 Z 应该回滚。

3- 异常发生在 X 提交之后且 Y 事务之间,但 Y 没有抛出它:仅 Y 应该回滚,X 和 Z 必须提交。

4- 异常发生在 Y 提交之后:X、Y 和 Z 应该回滚。

因此,我尝试在我的代码中处理所有这些情况并对其进行了测试;它有效!
我总是使用 LLBLGen Pro. 作为 ORM,当然你也可以在我的代码中看到它,但如果你不熟悉它,也不用担心,相关的代码很容易理解!

使用代码

我使用堆栈来处理嵌套事务。在每个 Start() 方法中,相关的事务标识符都会被推入其中,只有当堆栈为空时,才意味着不存在外部事务,所以我才启动一个真实的事务。

    /// <summary>

        /// starts a new Transaction or an inner Transaction

        /// </summary>

        /// <param name="isolationLevel"></param>

        public void Start(IsolationLevel isolationLevel)
        {
            string startMethodName = GetSavePoint();
            int transactionID = tarnsactionIDToInfoMap.Count + 1;

            if (transactionStack.Count == 0)
            {
                adapter.StartTransaction(isolationLevel, "1");
                tarnsactionIDToInfoMap.Clear();
            }
            else
            {
                adapter.SaveTransaction(transactionID.ToString());
            }

            tarnsactionIDToInfoMap.Add(transactionID, startMethodName);
            transactionStack.Push(transactionID);
        }

当调用 commit() 或 rollback() 时,会弹出一个事务,再次如果堆栈变为空,则意味着该事务是真实的,必须回滚或提交。

    /// <summary>

        /// Commits the mosty inner Transaction

        /// </summary>

        public void Commit()
        {
            if (transactionStack.Count == 0)
            {
                throw new FatalException("Error in transaction Handling. Commit on empty stack", true);
            }

            string commitMethodName = GetSavePoint();
            string srartMethodName = tarnsactionIDToInfoMap[(int)(transactionStack.Pop())].ToString();

            if (!commitMethodName.Equals(srartMethodName))
            {
                LogManager.Instance.WriteWarning("Unmatched transaction. " +
                    "The Start Transaction was called from " + srartMethodName +
                    " but it was commited in " + commitMethodName);
            }

            if (transactionStack.Count == 0)
            {
                adapter.Commit();
            }
        }

        /// <summary>

        /// Rolls back the mosty inner Transaction

        /// </summary>

        public void Rollback()
        {
            if (transactionStack.Count == 0)
            {
                throw new FatalException("Error in transaction Handling. Rollback on empty stack", true);
            }

            int transactionID = (int)(transactionStack.Pop());
            string rollbackMethodName = GetSavePoint();
            string startMethodName = tarnsactionIDToInfoMap[transactionID].ToString();

            if (!rollbackMethodName.Equals(startMethodName))
            {
                LogManager.Instance.WriteWarning("Unmatched transaction. " +
                    "The Start Transaction was called from " + startMethodName +
                    " but it was rolled back in " + rollbackMethodName);
            }

            if (transactionStack.Count == 0)
            {
                adapter.Rollback();
            }
            else
            {
                adapter.Rollback(transactionID.ToString());
            }
        } 
我希望这个类对您有所帮助!


© . All rights reserved.