交易升级至DTC,无多重连接。

3
有没有人知道,在使用事务范围时,如果没有打开多个连接,事务是否会升级到DTC。
我知道,如果在事务范围内打开多个连接(无论使用什么连接字符串),该事务很可能会被升级为DTC。
因此,我已经费尽心思,确保在我的事务中只有一个连接被打开。
然而,我的客户端出现了异常:
发生错误。Csla.DataPortalException:数据门户更新失败(基础提供程序在打开时失败。) ---> Csla.Reflection.CallMethodException:EditableCategory.DataPortal_Update方法调用失败 ---> System.Data.EntityException:基础提供程序在打开时失败。 ---> System.Transactions.TransactionManagerCommunicationException:分布式事务管理器(MSDTC)的网络访问已被禁用。请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问。 ---> System.Runtime.InteropServices.COMException:事务管理器已禁用其对远程/网络事务的支持。
我再次确认,在该范围内只有一个连接被打开。请看一下。
 protected override void DataPortal_Update()
    {
        using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, System.Transactions.TransactionManager.MaximumTimeout))
        {
            //get the dal manager he knows which dal implementation to use
            using (var dalMgr = DataAccess.BusinessObjectsDalFactory.GetManager())
            {
                //get the category dal implementation
                var ecDal = dalMgr.GetProvider<DataAccess.BusinessObjectDalInterfaces.ICategoryDAL>();

                //assume all the data is good at this point so use bypassproperty checks
                using (BypassPropertyChecks)
                {
                    var catData = new Models.Category { CategoryId = CategoryId, CategoryName = CategoryName, LastChanged = TimeStamp };

                    ecDal.UpdateCategory(catData);

                    TimeStamp = catData.LastChanged;
                }
            }

            ts.Complete();
        }

        base.DataPortal_Update();
    }

public class DalManager : Core.Sebring.DataAccess.IBusinessObjectsDalManager {private static string _typeMask = typeof(DalManager).FullName.Replace("DalManager", @"{0}");

public T GetProvider<T>() where T : class
{
  var typeName = string.Format(_typeMask, typeof(T).Name.Substring(1));
  var type = Type.GetType(typeName);
  if (type != null)
    return Activator.CreateInstance(type) as T;
  else
    throw new NotImplementedException(typeName);
}

public Csla.Data.DbContextManager<DataContext> ConnectionManager { get; private set; }

public DalManager()
{
    ConnectionManager = Csla.Data.DbContextManager<DataContext>.GetManager();
}

public void Dispose()
{
  ConnectionManager.Dispose();
  ConnectionManager = null;
}


public void UpdateDataBase()
{
    DatabaseUpgrader.PerformUpgrade();
}
}

 public void UpdateCategory(Models.Category catData)
    {
        if (catData == null) return;
        using (var cntx = DbContextManager<DataContext>.GetManager())
        {
            var cat = cntx.DbContext.Set<Category>().FirstOrDefault(c => c.CategoryId == catData.CategoryId);

            if (cat == null) return;

            if (!cat.LastChanged.Matches(catData.LastChanged))
                throw new ConcurrencyException(cat.GetType().ToString());

            cat.CategoryName = catData.CategoryName;
            //cntx.DbContext.ChangeTracker.DetectChanges();
            cntx.DbContext.Entry<Category>(cat).State = System.Data.EntityState.Modified;
            cntx.DbContext.SaveChanges();
            catData.LastChanged = cat.LastChanged;
        }

    }

DBContextManager的代码是可用的,但简单来说,它只是确保只有一个DBContext和一个打开的连接。我是否忽略了什么?我猜DBConextManager可能出了问题,所以我在CSLA论坛上发帖了(DBContextManager是CSLA的一部分)。但是有没有人遇到过这样的情况:他们确信在事务范围内只有一个连接打开,并且事务被升级为DTC?
当然,在我的本地开发机器或任何QA机器上都无法重现此异常。
感谢您的帮助。

1
这只是应用程序多个实例打开的情况,因此有多个数据库连接的可能吗? - Ryan Amies
谢谢你的建议。我没有考虑过那个问题。虽然我相当确定只有一个应用程序实例在运行。我会检查一下。由于我无法重现问题,必须盲目尝试,所以可能需要一段时间来验证,但我会及时向你报告。 - ARs
1个回答

0

当使用 System.Transactions.TransactionScope 进行事务处理时,Entity Framework 可能会随机尝试打开新连接。

尝试添加 finally 语句并释放您的事务,同时调用您的 dbContext 并手动关闭连接,这将减少事务升级的次数,但仍可能发生:

finally
            {
                cntx.Database.Connection.Close();
                transaction.Dispose();
            }

这是一个已知的“bug”,你可以在这里找到更多信息:

http://petermeinl.wordpress.com/2011/03/13/avoiding-unwanted-escalation-to-distributed-transactions/


你是说有时候EF 5会保持连接处于打开状态?所以在以下代码块中可能会打开多个连接?使用(DataContext dc = new DataContext()){ //多个查询、更新、删除、插入操作 } - ARs
MaG3Stican基本上是正确的。我曾经问过这个问题https://dev59.com/GXXYa4cB1Zd3GeqP-MYG,然后有人指向了我这些细节,http://www.digitallycreated.net/Blog/48/entity-framework-transactionscope-and-msdtc,最终回答了我的问题。 - ARs
每次执行select或update操作时,EF5都会打开一个连接,有时候会在之后关闭它,有时候会保持连接处于打开状态,直到上下文不再存在。 - Bryan Arbelo - MaG3Stican
实际上,这是SQL Server 2005、TranscationScope和EF5的问题。不,EF实际上没有留下打开的连接,也没有在TransactionScope中打开两个不同的连接,但事务仍然升级到了MSDTC。你可以在这里找到详细信息:http://www.digitallycreated.net/Blog/48/entity-framework-transactionscope-and-msdtc。一旦我安装了SQL Server 2005,我就能在我的开发环境中复现这个问题。感谢您的帮助。 - ARs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接