.net 关于事务和msdtc的混淆
对于事务和msdtc如何协同工作,我有一些基本的困惑 我有一个基本的服务器/客户端winforms应用程序。该应用程序使用transactionscope封装在sql server上执行的多个sql命令 当我仅在服务器上启用msdtc网络访问时,应用程序似乎工作正常。后来有一天,它停止工作,说没有启用网络访问 现在看来,为了让transactionscope正常工作,我必须在客户端计算机和服务器上启用msdtc网络访问 客户端或服务器msdtc服务是否执行事务工作?或者两者兼而有之.net 关于事务和msdtc的混淆,.net,winforms,transactions,msdtc,.net,Winforms,Transactions,Msdtc,对于事务和msdtc如何协同工作,我有一些基本的困惑 我有一个基本的服务器/客户端winforms应用程序。该应用程序使用transactionscope封装在sql server上执行的多个sql命令 当我仅在服务器上启用msdtc网络访问时,应用程序似乎工作正常。后来有一天,它停止工作,说没有启用网络访问 现在看来,为了让transactionscope正常工作,我必须在客户端计算机和服务器上启用msdtc网络访问 客户端或服务器msdtc服务是否执行事务工作?或者两者兼而有之 是否有人对客
是否有人对客户端和服务器或服务器都需要msdtc网络访问有指导意见?如果使用msdtc,则需要客户端(应用程序)和服务器(数据库)来运行msdtc并正确配置 这可能是痛苦的根源,尤其是在处理防火墙时。如果您遇到问题,请查看。它讨论BizTalk,但一般适用于MSDTC。他也是你的朋友 现在,如果您使用的是SQL Server 2005及更高版本,仅访问一个数据库,使用一个数据库连接,并且不在应用程序域之间传递事务,则不应要求使用MSDTC。在这种情况下,System.Transactions事务管理器将为您管理事务。如果出现上述任何情况,则事务将升级为分布式事务(事务管理器将为MSDTC)。有关更多信息,请参阅 一般来说,如果您不需要MSDTC,最好避免使用它。i、 e.如果您只处理一个SQL Server 2005+数据库,请尝试将代码设计为不使用MSDTC。除了配置方面的麻烦外,DTC还会对性能造成影响,因为对MSDTC的所有调用都是进程外的,再加上两阶段提交协议(MSDTC使用)的开销 就你的具体情况而言,这很难说。如果您的代码没有更改,那么防火墙规则可能已经更改了?我还看到Windows更新更改了DTC配置(出于安全考虑),这导致了一个问题 根据评论更新: 为了监视事务升级或升级,如果您不使用任何分布式事务,我认为您可以使用一些分布式事务协调器性能计数器来跟踪提交的事务。如果进行测试,您可以禁用MSDTC并查看代码是否失败。另一种方法是监视SQL Server中的事务。从编码的角度来看,您可以尝试处理事件并进行一些日志记录(但在投入生产之前删除该代码) 有关使用单个连接的代码示例,请转到MSDN页面。基本上,创建一个TransactionScope,创建一个SqlConnection,使用SqlConnection做一些工作,关闭连接,调用scope.Complete()
请注意,如果您使用的是数据适配器方法,它们会自动管理您的连接,从而关闭连接或将连接返回到连接池。无论哪种方式,如果调用另一个操作,则事务将升级为DTC事务。有关更多详细信息,请参阅。要扩展@Tuzo的解释,以下是一个始终升级的命令示例:
using(var scope = new TransactionScope())
{
using(var conn = new SqlConnection(connString)){
conn.Open();
//...some command, etc.
}
using(var conn = new SqlConnection(connString)){
conn.Open();
//...some command, etc.
}
scope.Complete();
}
在实践中,连接和命令将在另一个类中,等等,但是您知道了。即使连接字符串指向同一数据库,它也将使用DTC升级,因为它是两个连接。非升级交易包括:
using(var scope = new TransactionScope())
{
using(var conn = new SqlConnection(connString)){
conn.Open();
//...some command, etc.
//...some other command, etc.
}
scope.Complete();
}
无论如何,这是更好的代码,因为您可以打开连接,执行所需操作,然后尽快关闭。这意味着您必须仔细考虑您的连接管理。根据您的应用程序,您可能会以不同的方式实现此功能。例如:
using(var scope = new TransactionScope())
using(var conn = new SqlConnection(connString))
{
conn.Open();
var myService = new MyService(conn);
var myService2 = new MyService2(conn);
myService.DoSomething();
myService2.DoSomething();
scope.Complete();
}
有多种方法可以实现这一点。企业库数据访问应用程序块,各种ORM还可以帮助您更高效地处理连接和事务。更新:我发现了一篇文章,解释了为什么在TransactionScope内的同一数据适配器上同时使用GetData和Update以及解决方法时,事务会从LTM升级到MSDTC 权威的TableAdapters+事务博客文章 我理解一次打开多个连接升级要分发的事务的部分。但是,我遇到了一个问题,即只有一个连接和一个针对正在升级的数据库的查询。存储过程中也没有任何事务。如果有人有线索,我想听听。在我的代码示例中,“adapter.Update(table)”将触发分布式事务 我已经将代码的精髓从我现有的项目中带了出来,并简化了大部分正在进行的工作,但我仍然有同样的问题。这基本上是用一个表适配器创建一个数据集,并用一个存储过程将其设置为select、insert和delete。我选择与特定用户相关的所有记录。然后,根据其中一条记录是否存在“myPPID”,我添加或删除它。然后,我调用update方法,并通过观察组件服务中的事务统计信息来查看要分发的事务升级 我正在使用WindowsXPProSP3和.NETFramework3.5作为客户端程序。它通过局域网连接到SQL 2005数据库到Windows Server 2003 R2 Enterprise Edition SP2
private void button1_Click(object sender, EventArgs e)
{
int userId = 3;
int myPPId = 881;
using (TransactionScope ts = new TransactionScope())
{
using (DataSet1TableAdapters.AssignedPPTableAdapter adapter
= new MSDTCPromotionTest.DataSet1TableAdapters.AssignedPPTableAdapter())
{
using (DataSet1.AssignedPPDataTable table = adapter.GetData(userId))
{
DataSet1.AssignedPPRow row = table.FindByUserIdmyPPId(
userId, myPPId);
if (row == null)
{
table.AddAssignedPPRow(userId, myPPId, string.Empty,
string.Empty, true);
}
else
{
row.Delete();
}
adapter.Update(table);
}
ts.Complete();
}
}
}
连接字符串没有什么特殊之处:
<add name="ConnectionString" connectionString="
Data Source=devdb;
Initial Catalog="TEST MSDTC";
Integrated Security=True"
providerName="System.Data.SqlClient" />
阅读:
删除:
ALTER procedure [dbo].[p_UserForm_AssignedPP_Delete]
(
@Original_UserId INT,
@Original_MyPPId INT
)
AS
SET NOCOUNT ON;
DELETE FROM usermypp WHERE [UserID] = @Original_UserId
AND [MyPPID] = @Original_MyPPId
谢谢你的好消息。我不想使用MSDTC。我使用的是sql2005,1db,没有传递应用程序域,但不确定是否使用了1个连接。是否可以给出一个简短的示例,说明一个包含多个sql语句的事务不会被提升为dtc?是否有工具或任何其他方法
ALTER procedure [dbo].[p_UserForm_AssignedPP_SelectByUserId]
(
@UserId int
)
AS
SELECT
[UserId],
[myPPId],
'' Title,
'' Abbreviation,
0 IsArchived
from
UsermyPP unpp
where
unpp.[userid] = @UserId
ALTER procedure [dbo].[p_UserForm_AssignedPP_Delete]
(
@Original_UserId INT,
@Original_MyPPId INT
)
AS
SET NOCOUNT ON;
DELETE FROM usermypp WHERE [UserID] = @Original_UserId
AND [MyPPID] = @Original_MyPPId