服务器设置分布式事务(数据库开启分布式事务)

                              分布式事务方案

一、 概述(分布式事务)

                     

二、 分布式事务的注意项

  1. 事务尽可能短。

减少事务占用数据的时间,减短其他访问者等待时间。

  1. 事务隔离级别

 

三、 分布式事务基础设置

分布式事务基础设置是比较繁琐的,也是很容易出问题的一个环节,大体上从三方面入手。三方面首拼字母为SFM,我们所需要设置的正是SFM。

S:数据库

 

 

F:防火墙

添加msdtc到防火墙列外。

 

 

M:MSDTC分布式事务处理协调器

 

 

 

 

主意事项:(故障排查)

  1. 检测端口

数据库端口:1433

RPC服务通讯端口:135

telnet +IP+端口号

例如:telnet 192.168.1.64 135

  1. 检查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

  1. 存储过程(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只是基础测试,已调试成功,根据自己的业务需求不同,找到合适的方式和合理的代码结构。

  1. 能够通过调整业务结构、数据库结构避免分布式事务的,尽量不用分布式事务。
  2. 多数据库时才使用分布式事务,同一数据库,最好使用SqlTransaction。
  3. 分布式事务不支持跨域。
  4. 请注意MSDTC的设置和测试,详见第二章节。
  5. TransactionScopeNet2.0以上的版本才支持。

 

posted @ 2018-07-05 11:18  狼人666  阅读(398)  评论(0编辑  收藏  举报