分布式事务方案
     
    
     一、
     
      概述(分布式事务)
     
    
二、 分布式事务的注意项
- 事务尽可能短。
减少事务占用数据的时间,减短其他访问者等待时间。
- 事务隔离级别
     三、
     
      分布式事务基础设置
     
    
     
      分布式事务基础设置是比较繁琐的,也是很容易出问题的一个环节,大体上从三方面入手。三方面首拼字母为
     
     SFM,我们所需要设置的正是SFM。
    
S:数据库
      
    
F:防火墙
     
      添加
     
     msdtc到防火墙列外。
    
      
    
M:MSDTC分布式事务处理协调器
      
    
      
    
主意事项:(故障排查)
- 检测端口
     
      数据库端口:
     
     1433
    
RPC服务通讯端口:135
telnet +IP+端口号
例如:telnet 192.168.1.64 135
- 
      
 检查
 
 NetBIOS 名称是否解析IP 地址
     NetBIOS 名称:
     
      是
     
     Network Basic Input/Output System的简称,一般指用于局域网通信的一套API
    
     NetBIOS 名称是称作“完整计算机名称”的名称的第一部分,例如,如果“完整计算机名称”为 myserver.company.domain.com,则计算机的 NetBIOS 名称为 myserver
     
      。
     
    
检测方法:
1)在客户端计算机上启动命令提示符,键入以下命令,然后按Enter: ping <NetBIOS name of server computer>
ping命令的记过应该返回与服务器计算机相关联的IP。
2)在服务器计算机上启动命令提示符,键入以下命令,然后按Enter: ping <NetBIOS name of client computer>
ping命令的记过应该返回与客户端计算机相关联的IP。
     
      如果
     
     NetBIOS 名称解析在任何一个方向上不成功,或者反向名称查找失败,请在 DNS 服务器、NetBIOS 名称服务器、HOSTS 文件或 LMHOSTS 文件中添加适当的条目以纠正问题。
    
工具检测:
     
      如果在两台计算机中的一台上安装了
     
     SQL Server,则可以使用 DTCTester 实用程序检查这两台计算机之间是否支持事务处理。DTCTester实用程序使用 ODBC 检查 SQL Server 数据库是否支持事务处理。
    
     
      如果两台计算机中都没有安装
     
     SQL Server,则可以使用 DTCPing 检查这两台计算机之间是否支持事务处理。DTCPing 是在两台计算机中都没有安装 SQL Server 的情况下替代 DTCTester 实用程序的良好工具,使用时必须既在客户端计算机上运行,也在服务器计算机上运行。
    
四、 实现方式
1. Sql语句来使用事务
sqlserver2005/2008中支持,sqlserver 2000上不支持(try…… catch)
set xact_abort ON
begin try
begin tran
update [192.168.1.57].db_wps.dbo.wps_role set R_name = ‘57575757’ where R_ID =11;
update [192.168.1.52].db_wps.dbo.wps_role set R_name = ‘55255252’ where R_ID =11;
–RAISERROR (‘Error raised in TRY block.’,16,1);
commit tran
end try
begin catch
rollback tran
end catch
     
      注意:注意直接用
     
     server
     
      名称
     
     [192.168.1.52]夸服务器操作,需要调用如下存储过程:
    
exec sp_addlinkedserver ‘192.168.1.52’, ‘ ‘, ‘SQLOLEDB ‘, ‘192.168.1.82’
exec sp_addlinkedsrvlogin ‘192.168.1.52’, ‘false ‘,null, ‘sa’, ‘Aa123456’
     2.NET—- SqlTransaction
     
      或者
     
     NET—- TransactionScope
    
添加引用System.Transactions.dll;
引用using System.Transactions;
     SqlConnection  sqlConn = new SqlConnection( ConfigurationManager.ConnectionStrings[“ConnStr”].ConnectionString);
     
     SqlTransaction  sqlTrans = null;
    
try {
sqlConn.Open();
     sqlTrans = sqlConn.BeginTransaction();
     
     //
     
      事务开始
     
     
     SqlCommand sqlComm = new SqlCommand(“”, sqlConn, sqlTrans);
    
sqlComm.CommandTimeout = 120;
     sqlComm.CommandType = System.Data.CommandType.Text;
     
     string insertSql = ” update [192.168.1.57]db_wps.dbo.wps_role set R_name = ‘57575757’ where R_ID =11″;
     
     string updateSql = “update[192.168.1.52].db_wps.dbo.wps_role set R_name = ‘55255252’ where R_ID =11;”;
     
     sqlComm.CommandText = insertSql; sqlComm.ExecuteNonQuery();
     
     //
     
      执行
     
     
     insert sqlComm.CommandText = updateSql; sqlComm.ExecuteNonQuery();
     
     //
     
      执行
     
     update //throw new Exception(“test exception.the transaction must rollback”);
     
     sqlTrans.Commit();//
     
      事务提交
     
     
     } catch (Exception ex)
     
     {
     
     
     sqlTrans.Rollback();//
     
      事务回滚
     
     
     Console.WriteLine(ex.Message);
     
     }
     
     finally
     
     {
     
     if (sqlConn.State != System.Data.ConnectionState.Closed)
     
     sqlConn.Close();
     
     }
    
五、 DEMO
- 存储过程(192.168.1.64 DB_WPS )
     WPS_DistributedTransaction
     
      :批量
     
     SQL语句,事务执行。
    
USE [DB_WPS]
GO
/****** Object: StoredProcedure [dbo].[WPS_DistributedTransaction] Script Date: 10/30/2014 16:01:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
— Batch submitted through debugger: SQLQuery10.sql|7|0|C:\Users\Administrator\AppData\Local\Temp\2\~vs4060.sql
— =============================================
— Author: <Author,,Name>
— Create date: <Create Date,,>
— Description: <Description,,>
— =============================================
ALTER PROCEDURE [dbo].[WPS_DistributedTransaction]
(
     @Sql varchar(max),–sql
     
      字符串组合,表名格式:
     
     
      server.database.table
     
    
     @split varchar(2), —
     
      分隔符
     
    
     @result int out  —
     
      成功返回,失败返回
     
    
)
AS
BEGIN
     —
     
      当
     
     
      SET NOCOUNT
     
     
      为
     
     
      ON
     
     
      时,不返回计数(语句影响的行数)。
     
    
SET NOCOUNT ON;
     —
     
      如果执行
     
     
      Transact-SQL
     
     
      语句产生运行时错误,则整个事务将终止并回滚。
     
    
SET XACT_ABORT ON;
     —
     
      标记分割符位置
     
    
declare @location int
     —
     
      标记
     
     起始
     
      位置
     
    
declare @start int
–分隔符长度
declare @seed int
–执行的语句
declare @execsql varchar(1000)
set @Sql=ltrim(rtrim(@Sql))
set @start=1
set @seed=len(@split)
set @location=charindex(@split,@Sql)
begin try
begin tran
set @numere = LEN(@Sql)
while @location<>0 and @location < @numere
begin
set @location=charindex(@split,@Sql,@start)
if(@location = 0)
set @location = @numere +1
set @execsql = substring(@Sql,@start,@location-@start)
exec(@execsql)
set @start=@location+@seed
end
commit tran
set @result = 1
end try
begin catch
–此处写表,记录错误信息(省略)
rollback tran
set @result = 0
end catch
— Insert statements for procedure here
END
     
      分析:如果记录详细的错误信息,由于存储过程不支持数组类型,建议传递
     
     XML
     
      参数。
     
    
2.NET—- TransactionScope
     //
     
      测试多数据库链接
     
    
public void TestSqlTransaction ()
     {
     
    
string errorString = string.Empty;
try
     {
     
    
using (TransactionScope scope = new TransactionScope())
     {
     
    
     //
     
      更新
     
     
      192.168.1.57
     
     
      数据库的
     
     
      DB_WPS
     
     
      表
     
    
//using (SqlConnection conOne = new SqlConnection(“Data Source=192.168.1.57;database=DB_WPS;User ID=sa;Password=Aa123456”))
using (SqlConnection conOne = new SqlConnection(“Data Source=10.10.30.71;database=DB_WPS;User ID=sa;Password=Aa123456”))
     {
     
    
conOne.Open();
SqlCommand command = new SqlCommand(“update db_wps.dbo.wps_role set R_name = ‘57575757’ where R_ID =11”, conOne);
int i = command.ExecuteNonQuery();
}
     //
     
      更新
     
     
      192.168.1.52
     
     
      数据库的
     
     
      DB_WPS
     
     
      表
     
    
using (SqlConnection conTwo = new SqlConnection(“Data Source=10.10.30.72;database=DB_WPS;User ID=sa;Password=Aa123456”))
     {
     
    
conTwo.Open();
// SqlCommand command = new SqlCommand( “update db_wps.dbo.wps_role set R_name = ‘55255252’ where R_ID =11”, conTwo);
SqlCommand command = new SqlCommand(“update db_wps.dbo.wps_role set R_name = ‘000000000000000’ where R_ID =11”, conTwo);
int i = command.ExecuteNonQuery();
}
     scope.Complete();  //
     
      提交事物
     
    
}
}
     catch (Exception ex)       //
     
      发生异常后自动回滚
     
    
     {
     
    
MessageBox.Show(ex.Message);
MessageBox.Show(errorString);
//throw;
}
}
     
      优缺点分析:存储过程运行速度较快,
     
     Net
     
      机制事务运行速度稍慢。
     
    
     
      存储过程难处理复杂的业务流程,存储过程管理较为麻烦
     
    
六、 总结
     
      本文
     
     DEMO只是基础测试,已调试成功,根据自己的业务需求不同,找到合适的方式和合理的代码结构。
    
- 能够通过调整业务结构、数据库结构避免分布式事务的,尽量不用分布式事务。
- 
      
 多数据库时才使用分布式事务,同一数据库,最好使用
 
 SqlTransaction。
- 分布式事务不支持跨域。
- 
      
 请注意
 
 MSDTC的设置和测试,详见第二章节。
- 
      TransactionScope
 
 在
 
 Net2.0以上的版本才支持。
转载于:https://www.cnblogs.com/guangang/articles/9267346.html
 
