分布式事务方案
一、 概述(分布式事务)
二、 分布式事务的注意项
- 事务尽可能短。
减少事务占用数据的时间,减短其他访问者等待时间。
- 事务隔离级别
三、 分布式事务基础设置
分布式事务基础设置是比较繁琐的,也是很容易出问题的一个环节,大体上从三方面入手。三方面首拼字母为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
ping命令的记过应该返回与服务器计算机相关联的IP。
2)在服务器计算机上启动命令提示符,键入以下命令,然后按Enter: ping
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:
-- Create date:
-- 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以上的版本才支持。