错误 - 具有多个数据库连接的 LINQ/TransactionScope
Posted
技术标签:
【中文标题】错误 - 具有多个数据库连接的 LINQ/TransactionScope【英文标题】:Error - LINQ/TransactionScope with multiple database connections 【发布时间】:2012-06-28 10:50:30 【问题描述】:我在将几个事务包装到同一个 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;
注意事项:
-
我有几种不同的删除方法,它们都在 TransactionScope 之外工作。
ProfileInfo 是主配置文件表,对于 Live 和 Archive 数据库大致相同。
非常感谢任何帮助!非常感谢...
【问题讨论】:
运行 MSDTC 的帐户是否具有访问数据库的正确权限? 您的归档在客户端逐行进行,并且在两个并置的数据库之间进行 DTC?当您只有一把锤子时...您不必将 EF 用于一切。尝试在服务器端进行。DELETE ... OUTPUT ... INTO targetdb... FROM sourcedb ... WHERE
将是一个很好的起点。 SSIS 工作是另一个很好的选择。甚至是基于 T-SQL 游标的解决方案。只是不要通过客户端路由每一行......
@Kane - 我相信是的。我已经克服了另外 2 个与 MSDTC 相关的错误。 -“分布式事务管理器 (MSDTC) 的网络访问已被禁用。请使用组件服务管理工具在 MSDTC 的安全配置中启用 DTC 进行网络访问。”和“合作伙伴事务管理器已禁用对远程/网络事务的支持。”现在它调用 Delete 方法并得到我发布的错误 - “与底层事务管理器的通信失败。”
@Remus - 另一个人告诉我,LINQ 有它的位置,但它不是一切。我不是一个 SQL 脚本编写者,但如果这更有意义,那么这就是我要做的。我昨天就是这样倾斜的,如果这是最有意义的,我可能会这样做。如果存在限制、错误等,我想从中学习。从我读到的内容来看,这个“应该”按原样工作。
@TravelDev:它会起作用的。但它的性能将比它可能低一两个数量级。当您可以编写有用的代码时,您将不得不解决诸如 DTC 协调之类的问题。
【参考方案1】:
我决定将其发布为答案,而不是继续纵横交错。
不要使用错误代码。这就是例外的原因。代码流更难阅读,错误代码返回邀请被忽略。异常使代码更易于阅读并且更不容易出错。
如果您使用 TransactionScope,请记住始终明确设置隔离级别。见using new TransactionScope() Considered Harmful。 SERIALIZABLE 的隐式隔离级别几乎从不需要,并且具有巨大的负面规模影响。
交易升级。每当在事务范围内打开多个连接时,它们都可以将事务升级为分布式事务。行为因版本而异,有些人试图记录它,例如。 TransactionScope: transaction escalation behavior:
SQL Server 2008 比 SQL Server 2005 更智能,并且可以 自动检测是否所有数据库连接在某个 事务指向同一个物理数据库。如果是这种情况, 该事务仍然是本地事务,并且不会升级到 分布式事务。不幸的是,有一些警告:
如果打开的数据库连接是嵌套的,事务仍然是 升级为分布式事务。 如果在事务中,一个 连接到另一个持久资源,事务是 立即升级为分布式事务。
由于您的连接(来自使用的两个数据上下文)指向不同的数据库,即使在 SQL Server 2008 上,您的 TransactionScope 也会升级为分布式事务。
将您的应用程序加入 DTC 至少在两个方面有害:
吞吐量会从地板下沉。一个数据库每秒可以支持几千个本地事务,但每秒只能支持几十个(可能低到几百个)分布式事务。这主要是因为two phase commit 的复杂性。 DTC 需要协调员:MSDTC。 [对 MSDTC 进行的安全性增强] 使配置更具挑战性,开发人员发现他们的应用程序中需要 MSDTC 肯定是出乎意料的。 链接文章中描述的步骤可能是您现在所缺少的。对于 Windows Vista/Windows 7/Windows Server 2008/Windows Server 2008R2,这些步骤在 MSDTC in Windows Vista and Windows Server 2008、How to configure DTC on Windows 2008 和其他类似文章中进行了描述。现在,如果您按照上述文章修复 MSDTC 通信,您的代码应该可以正常工作,但我仍然认为此归档应该不发生在运行 EF 的客户端代码中。有更好的工具,SSIS 就是一个很好的例子。运行 SSIS 的夜间计划作业会更有效地传输那些未使用的配置文件。
【讨论】:
这很有帮助。我会把它作为答案以上是关于错误 - 具有多个数据库连接的 LINQ/TransactionScope的主要内容,如果未能解决你的问题,请参考以下文章
错误 3296:具有多个 JOIN 的 MS Access 查询中不支持连接表达式