9

我在用:

public class TransactionUtils
{
    public static TransactionScope CreateTransactionScope()
    {
        var TransactionOptions = new TransactionOptions();
        TransactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
        TransactionOptions.Timeout = TimeSpan.MaxValue;
        return new TransactionScope(TransactionScopeOption.Required, TransactionOptions);
    }
}

创建我的所有交易。我面临的问题是当我嵌套 2 时TransactionUtils.CreateTransactionScope()出现错误:Time-out interval must be less than 2^32-2. Parameter name: dueTm. 我假设这是因为它试图将子事务附加到父事务,并且合并的超时时间很大。

有没有办法判断新创建的事务是否是嵌套事务,这样我就可以避免设置超时?

另一种方法是传递一个参数,CreateTransactionScope()这样我就可以告诉它它是嵌套的并且不设置超时,但我宁愿找到一种自动处理它的方法。

4

2 回答 2

34

有一个非常简单的答案:

System.Transactions.Transaction.Current != null

这从 Framework 2.0 开始有效。

我不确定为什么其他答案会如此深入地创建链接到非公共领域的 IL。

于 2013-03-22T20:45:30.767 回答
1

是的,这是可能的。我有以下代码。我不是自己做的,但忘记了我从哪里得到的。感谢原作者,但我记得我只是在谷歌上搜索它。我将它用于.net 4.0,不知道它与其他版本的兼容性如何(它取决于特定程序集中的特定类)。

使用下面的代码,您可以检查代码中的某个点是否在“内部”事务范围内执行。

class TransactionScopeDetector {
    private Func<TransactionScope> _getCurrentScopeDelegate;

    public bool IsInsideTransactionScope {
        get {
            if (_getCurrentScopeDelegate == null) {
                _getCurrentScopeDelegate = CreateGetCurrentScopeDelegate();
            }

            TransactionScope ts = _getCurrentScopeDelegate();
            return ts != null;
        }
    }

    private Func<TransactionScope> CreateGetCurrentScopeDelegate() {
        DynamicMethod getCurrentScopeDM = new DynamicMethod(
          "GetCurrentScope",
          typeof(TransactionScope),
          null,
          this.GetType(),
          true);

        Type t = typeof(Transaction).Assembly.GetType("System.Transactions.ContextData");
        MethodInfo getCurrentContextDataMI = t.GetProperty(
          "CurrentData",
          BindingFlags.NonPublic | BindingFlags.Static)
          .GetGetMethod(true);

        FieldInfo currentScopeFI = t.GetField("CurrentScope", BindingFlags.NonPublic | BindingFlags.Instance);

        ILGenerator gen = getCurrentScopeDM.GetILGenerator();
        gen.Emit(OpCodes.Call, getCurrentContextDataMI);
        gen.Emit(OpCodes.Ldfld, currentScopeFI);
        gen.Emit(OpCodes.Ret);

        return (Func<TransactionScope>)getCurrentScopeDM.CreateDelegate(typeof(Func<TransactionScope>));
    }
}
于 2012-12-12T10:15:39.000 回答