4

我在同一个 SQL Server 上将几个事务包装到 2 个不同的数据库中度过了愉快的时光。我最初在访问网络 DTC 时遇到问题,我解决了这个问题。现在,我继续得到的错误是“与底层事务管理器的通信失败”。

我们在数据库中有一些客户资料,当这些资料过时时,我们希望将它们移动到“存档”数据库进行存储。移动只是(幽默的斜体)将它们添加到存档数据库并从主/实时数据库中删除它们。我为每个数据库都有一个 DataContext。下面的代码在尝试使用第二个 DataContext 时执行 Add,然后在 Delete 上出现错误。我只使用 LINQ 几个月,过去几天我一直在搜索文章。我想知道我的代码是否有问题,或者 DTC 是否仍然存在未正确配置的内容?

我们在 VMware 上运行我的工作站和服务器。- 工作站是 Windows 7 SP1 - 服务器是 Windows 和 SQL Server 2008R2

“移动”的常规:

private int MoveProfileToArchiveDB( int iProfileId )
{
    int rc = RC.UnknownError;

    // get new Archive profile object
    ProfileArchive.ProfileInfo piArchive = new ProfileArchive.ProfileInfo();

    // 'Live' DataContext
    using ( ProfileDataContext dbLive = new ProfileDataContext() )
    {
        // get Live profile
        ProfileInfo piLive = ProfileInfo.GetProfile( dbLive, iProfileId );

        // copy Live data to Archive profile object... including the id
        ProfileArchive.ProfileInfo.CopyFromLive( piLive, piArchive, true );
    }

    bool bArchiveProfileExists = ProfileArchive.ProfileInfo.ProfileExists( piArchive.id );

    // make the move a transaction... 
    using ( TransactionScope ts = new TransactionScope() )
    {
        // Add/Update to Archive db
        using ( ProfileArchiveDataContext dbArchive = new ProfileArchiveDataContext() )
        {
            // if this profile already exists in the Archive db...
            if ( bArchiveProfileExists )
            {
                // update the personal profile in Archive db
                rc = ProfileArchive.ProfileInfo.UpdateProfile( dbArchive, piArchive );
            }
            else
            {
                // add this personal profile to the archive db
                int iArchiveId = 0;
                piArchive.ArchiveDate = DateTime.Now;
                rc = ProfileArchive.ProfileInfo.AddProfile( dbArchive, piArchive, ref iArchiveId );
            }

            // if Add/Update was successful...
            if ( rc == RC.Success )
            {
                // Delete from the Live db
                using ( ProfileDataContext dbLive = new ProfileDataContext() )
                {
                    // delete the personal profile from the Profile DB
                    rc = ProfileInfo.DeleteProfileExecCmd( dbLive, iProfileId );    // *** ERROR HERE ***
                    if ( rc == RC.Success )
                    {
                        // Transaction End (completed)
                        ts.Complete();
                    }
                }
            }
        }

    }

    return rc;
}

笔记:

  1. 我有几种不同的删除方法,它们都在 TransactionScope 之外工作。
  2. ProfileInfo 是主要的配置文件表,对于 Live 和 Archive 数据库大致相同。

任何帮助是极大的赞赏!非常感谢...

4

1 回答 1

8

我没有继续交叉评论,而是决定将其发布为答案。

  • 不要使用错误代码。这就是例外的原因。代码流更难阅读,错误代码返回邀请被忽略。异常使代码更容易阅读并且更不容易出错。

  • 如果您使用 TransactionScope,请记住始终明确设置隔离级别。请参阅使用新的 TransactionScope() 被认为是有害的。SERIALIZABLE 的隐式隔离级别几乎从未被要求,并且具有巨大的负面规模影响。

  • 交易升级。每当在事务范围内打开多个连接时,它们都可以将事务升级为分布式事务。行为因版本而异,有些人试图记录它,例如。TransactionScope:事务升级行为

SQL Server 2008 比 SQL Server 2005 智能得多,可以自动检测某个事务中的所有数据库连接是否都指向同一个物理数据库。如果是这种情况,事务仍然是本地事务,并且不会升级为分布式事务。不幸的是,有一些警告:

  • 如果打开的数据库连接是嵌套的,事务仍会升级为分布式事务。
  • 如果在事务中与另一个持久资源建立了连接,则事务会立即升级为分布式事务。

由于您的连接(来自使用的两个数据上下文)指向不同的数据库,因此即使在 SQL Server 2008 上,您的 TransactionScope 也会升级为分布式事务。

将您的应用程序加入 DTC 至少在两个方面是有害的:

  • 吞吐量将通过地板下沉。一个数据库每秒可以支持几千个本地事务,但每秒只能支持几十个(可能低到几百个)分布式事务。这主要是因为两阶段提交的复杂性。
  • DTC 需要协调员:MSDTC。[对 MSDTC 进行的安全性增强] 使配置更具挑战性,开发人员发现他们的应用程序中需要 MSDTC 肯定是出乎意料的。链接的文章中描述的步骤可能是您现在所缺少的。对于 Windows Vista/Windows 7/Windows Server 2008/Windows Server 2008R2 ,Windows Vista 和 Windows Server 2008 中的 MSDTC如何在 Windows 2008 上配置 DTC和其他类似文章中描述了这些步骤。

现在,如果您按照上述文章修复 MSDTC 通信,您的代码应该可以正常工作,但我仍然认为在运行 EF 的客户端代码中不应发生此归档。有更好的工具,SSIS就是一个很好的例子。运行 SSIS 的夜间计划作业将更有效地传输那些未使用的配置文件。

于 2012-06-27T20:22:54.223 回答