工作中遇到这样的情况,需要在更新表TableA(位于服务器ServerA 172.16.8.100中的库DatabaseA)同时更新TableB(位于服务器ServerB 172.16.8.101中的库DatabaseB)。

TableA与TableB结构相同,但数据数量不一定相同,应为有可能TableC也在更新TableB。由于数据更新不频繁,为简单起见想到使用了触发器Tirgger。记录一下遇到的一些问题:

1. 访问异地数据库

在ServerA 中创建指向ServerB的链接服务器,并做好账号映射。addlinkedserver存储过程创建一个链接服务器,参数详情参见官方文档。第1个参数LNK_ServerA是自定义的名称;第2参数产品名称,如果是SQL Server不用提供;第3个参数是驱动类型;第4个参数是数据源,这里写SQL Server服务器地址

exec sp_addlinkedserver 'LNK_ServerB_DatabaseB','','SQLNCLI','172.16.8.101'

配置链接服务器后,默认使用同一本地账号登陆远程数据库,如果账号有不同,还需要进行账号映射。sp_addlinkedsrvlogin参数详情参见官方文档。第1个参数同上;第2个参数false即使用后面参数提供的用户密码登陆;第3个参数null使所有本地账号都可以使用后面的用户密码来登陆链接服务器,如果第3个参数设置为一个本地SQL Server登陆用户名,那么只有这个用户才可以使用远程账号登陆链接服务器;最后两个是登录远程服务器的用户和密码。

exec sp_addlinkedsrvlogin 'LNK_ServerB_DatabaseB','false',null,'user','password'

如果要删除以上配置可以如下

exec sp_droplinkedsrvlogin 'LNK_ServerB_DatabaseB',null
exec sp_dropserver 'LNK_ServerB_DatabaseB','droplogins'

上面的配置在SQL Server Management Studio管理器里Server Objects下LinkedServers可以查询到,如果一切链接正常,可以直接打开链接服务器上的库表

值得注意的是以上两个存储过程不能出现在触发器代码中,而是事先在服务器ServerA中运行完成配置,否则触发器隐式事务的要求会报错“The procedure 'sys.sp_addlinkedserver' cannot be executed within a transaction.”

2. 配置分布式事务

SQL Server的触发器是隐式使用事务的,链接服务器是远程服务器,需要在本地服务器和远程服务器之间开启分布式事务处理,否则会报“The partner transaction manager has disabled its support for remote/network transactions”的错误。我在ServerA和ServerB中都开启分布式事务协调器,并进行适当配置,以支持分布式事务。ServerA和ServerB都是Windows Server 2012 R2,其他版本服务器类似。

(1)首先在Services.msc中确认Distributed Transaction Coordinator已经开启,其他版本的服务器不一定默认安装,需要安装windows features的方式先进行该特性的安装。

(2)在服务器管理工具Administrative Tools中找到Component Services,在Local DTC中属性Security选项卡中配置如下,打开相关安全设置,完成后会重启服务,也有文档称需要重启服务器,但是至少2012 R2不用。

(3)配置防火墙,Inbound和Outbound都打开

3. 数据库字段text, ntext的处理

业务中表TableA中有一个Content字段是ntext类型,同步到TableB时需要对内容做一些替换处理。对于text和ntext类型是一个过时的类型,微软官方建议用(N)VARCHAR(MAX)替换,可查阅这里。今后设计时可以考虑,这里我们考虑对ntext进行处理。

但是在触发器中,inserted和deleted表都是不允许对text/ntext/image类型进行处理的,这里我们采用一个曲线救国的办法,从数据库中把记录读取到临时表中,然后通过textptr和patindex函数和updatetext命令完成字符串替换处理

if exists(select * from tempdb..sysobjects where id=object_id('tempdb..#temp_tablea'))
drop table #temp_tablea
select * into #temp_tablea from TableA where ID = @ID
declare @s varchar(200),@d varchar(200)
select @s='/_target/',@d='/_replacement/'
declare @p varbinary(16),@postion int,@l int
select @p=textptr(Content),@l=len(@s),@postion=patindex('%'+@s+'%',Content)-1 from #temp_tablea
while @postion>0
begin
updatetext #temp_tablea.Content @p @postion @l @d
select @postion=patindex('%'+@s+'%',Content)-1 from #temp_tablea
end

特别注意以上代码对于text类型处理中文时会出问题,由于text存储non-unicode的数据,patindex会将中文字符解释为1个字符,而updatetext命令却将中文字符解释为2个字符。SQL Server 2005以上版本可以这样做替换:

update #temp_tablea set Content=cast(replace(cast(Content as nvarchar(max)),@s,@d) as text)

4. 执行远程数据库操作

当配置链接服务器时,我们可以直接访问远程数据库表了,如下

insert into LNK_ServerB_DatabaseB.DatabaseB.dbo.TableB ...
update LNK_ServerB_DatabaseB.DatabaseB.dbo.TableB set ...

但简陋的SQL编辑器往往会对语法报错,另外为方便编程,我们希望通过exec sp_executesql的方式获得更多的灵活性。其实exec就可以直接执行sql语句,但如果有返回值就比较困难了。如下,从远程服务器上通过ID查询表TableB后返回Name,sp_executesql存储过程可以使用output关键字定义变量为返回变量,其中@Name output为返回变量,@ID则是传入变量。

declare @sql nvarchar(500), @Name nvarchar(50),@ID nvarchar(40)
set @SQL=N'select @Name=Name from LNK_ServerB_DatabaseB.DatabaseB.dbo.TableB where ID=@ID'
exec sp_executesql @SQL,N'@Name nvarchar(50) output,@ID nvarchar(40)',@Name output,@ID

另外exec直接执行sql语句,本质上是执行拼接后的sql字符串,有时将变量拼接进字符串会困难的多(到底需要几个单引号),而sp_executesql则清晰多了

declare @SQL nvarchar(500),@Name nvarchar(50),@Count int,@ID nvarchar(40)
set @Name=N'Cat'
set @Count=0
set @ID=N'{00000000-0000-0000-0000-000000000000}'
set @SQL=N'update TableA set Name='''+@Name+''', Count='+@Count+' where ID='''+@ID+''''
exec(@SQL)
set @SQL=N'update TableA set Name=@Name,Count=@Count where ID=@ID'
exec sp_executesql @SQL, N'@Name nvarchar(50),@Count int,@ID nvarchar(40)',@Name,@Count,@ID

SQL Server实时同步更新远程数据库遇到的问题的更多相关文章

  1. 关于SQL Server 2005 的自动远程数据库备份

    原文:(原创)关于SQL Server 2005 的自动远程数据库备份 由于项目需要,需要对目标服务器上的数据库每天进行备份并转移,查阅网上的一些帮助,结合自己的实际需要,写了这篇文章,希望对有同样需 ...

  2. (原创)关于SQL Server 2005 的自动远程数据库备份

    由于项目需要,需要对目标服务器上的数据库每天进行备份并转移,查阅网上的一些帮助,结合自己的实际需要,写了这篇文章,希望对有同样需求的朋友有所帮助.目标服务器:192.168.1.197,备份服务器:1 ...

  3. SQL Server 2008 R2如何开启数据库的远程连接

    SQL Server 2008 R2如何开启数据库的远程连接 SQL Server 2005以上版本默认是不允许远程连接的,如果想要在本地用SSMS连接远程服务器上的SQL Server 2008,远 ...

  4. Oracle DBLink跨数据库访问SQL server数据同步 踩坑实录

    项目需求:这里暂且叫A公司吧,A公司有一套人事管理软件,需要与我们公司的软件做人员信息同步,A公司用的是SQL server数据库,我们公司用的Oracle,接口都不会开发(一万句"fuck ...

  5. SQL SERVER 2005 同步复制技术(转)

    SQL SERVER 2005 同步复制技术 以下实现复制步骤(以快照复制为例) 运行平台SQL SERVER 2005 一.准备工作: 1.建立一个 WINDOWS 用户,设置为管理员权限,并设置密 ...

  6. SQL Server 复制 - 发布订阅(SQL Server 数据同步)

    原文:SQL Server 复制 - 发布订阅(SQL Server 数据同步) SQL Server的同步是通过SQL Server自带的复制工具来实现的,分发布和订阅2大步. A,复制-发布 发布 ...

  7. SQL Server 2005同步复制

    原文:SQL Server 2005同步复制 以下实现复制步骤(以快照复制为例) 运行平台SQL SERVER 2005 一.准备工作: 1.建立一个 WINDOWS 用户,设置为管理员权限,并设置密 ...

  8. 对Oracle 、SQL Server、MySQL、PostgreSQL数据库优缺点分析

    对Oracle .SQL Server.MySQL.PostgreSQL数据库优缺点分析 Oracle Database Oracle Database,又名Oracle RDBMS,或简称Oracl ...

  9. SQL Server AlwaysON 同步模式的疑似陷阱

    原文:SQL Server AlwaysON 同步模式的疑似陷阱 SQL Server 2012 推出的最重要的功能之一Alwayson,是一个集之前Cluster和Mirror于一体的新功能,即解决 ...

随机推荐

  1. 关于UDP很好的书籍和文章(整理、持续更新)

    文章 告知你不为人知的 UDP:疑难杂症和使用(必看)

  2. 如何以Root权限在Pycharm上Run、Debug

    Pycharm官网提问:https://intellij-support.jetbrains.com/hc/en-us/community/posts/206587695-How-to-run-deb ...

  3. Binding.RelativeSource 属性

    Binding.RelativeSource 属性说明: 通过指定绑定源相对于绑定目标的位置,获取或设置绑定源. 此属性通常用于将对象的某个属性绑定到该对象的另一个属性,或用于在样式或模板中定义绑定. ...

  4. 各种排序算法思想复杂度及其java程序实现

    一.冒泡排序(BubbleSort)1. 基本思想: 设排序表长为n,从后向前或者从前向后两两比较相邻元素的值,如果两者的相对次序不对(A[i-1] > A[i]),则交换它们, 其结果是将最小 ...

  5. Mac下安装pcl-1.8.0

    更新,官方有Homebrew安装教程: http://pointclouds.org/documentation/tutorials/installing_homebrew.php#installin ...

  6. IOS-static cell 与 dynamic cell 混合使用

    static cell 与 dynamic cell 混合使用 关于静态cell与动态cell的混合使用,google一下便会有很多相关文章,这里也是看过一些前辈的经验(已经忘记具体是从哪篇文章得到的 ...

  7. IOS-网络(HTTP请求、同步请求、异步请求、JSON解析数据)

    // // ViewController.m // IOS_0129_HTTP请求 // // Created by ma c on 16/1/29. // Copyright © 2016年 博文科 ...

  8. Eclipse中配置Solr源码

    转自 http://hongweiyi.com/2013/03/configurate-solr-src-in-eclipse/ 1. 下载solr的src包,并解压 2. 解压后,在解压后的根目录执 ...

  9. jstree 取消选中父节点

    问题说明: 当选择子节点时,它的父节点只有一个子节点的情况下,默认会选中父节点. 当前应用场景: 不需要选中当前的父节点 实验截图: 修改部分: jstree.js 信息

  10. DbVisualizer 连接 SQL Server 2008配置

    软件准备 1.SQLServer驱动准备,可在该连接下载:https://pan.baidu.com/s/1i4V1Ivz (1). 解压JDBC for SQLServer drive.rar,得到 ...