当前位置: 首页 > 科技观察

SQL Server实时同步更新远程数据库遇到的问题

时间:2023-03-12 03:38:25 科技观察

SQLServer实时同步更新远程数据库遇到的问题库DatabaseB)。TableA和TableB的结构相同,但数据量不一定相同。应该有可能TableC也在更新TableB。由于数据不经常更新,为简单起见,使用触发器Tirgger。记录下遇到的一些问题:1.访问远程数据库,在ServerA中创建一个指向ServerB的链接服务器,并做账号映射。addlinkedserver存储过程创建链接服务器,参数详见官方文档。第一个参数LNK_ServerA是自定义名称;第二个参数产品名称,如果是SQLServer则不需要提供;第三个参数是驱动类型;第四个参数是数据源,这里写SQLServer服务器地址execsp_addlinkedserver'LNK_ServerB_DatabaseB','','SQLNCLI','172.16.8.101'配置好链接服务器后,使用同一个本地账号登录远程默认情况下的数据库。如果账户不同,还需要账户映射。sp_addlinkedsrvlogin参数详见官方文档。第一个参数同上;第二个参数false表示使用后一个参数提供的用户密码登录;第三个参数null使所有本地账户都可以使用后面的用户密码登录链接服务器,如果第三个参数设置为一个本地SQLServer登录用户名,则只有该用户可以使用远程账户登录到链接服务器;最后两个是登录远程服务器的用户名和密码。execsp_addlinkedsrvlogin'LNK_ServerB_DatabaseB','false',null,'user','password'如果要删除上面的配置,可以如下操作:LinkedServers可以在Objects下查询。如果所有链接都正常,可以直接打开链接服务器上的库表。值得注意的是,以上两个存储过程不能出现在触发器代码中,而是提前运行在服务器ServerA中完成配置,否则触发器隐式事务的要求会报错“Theprocedure'sys.sp_addlinkedserver'不能在交易中执行。”2.配置分布式事务的触发器SQLServer隐式使用事务,链接服务器是远程服务器,这就需要Enabledistributedtransactionprocessingbetweenlocalserverandtheremoteserver,否则会报错“伙伴事务管理器已禁用其支持远程/网络事务”将被报告。我在ServerA和ServerB中都启用了分布式事务协调器,并对其进行适当配置以支持分布式事务。ServerA和ServerB都是WindowsServer2012R2,其他版本服务器类似。(1)首先确认在Services.msc中已经启用了DistributedTransactionCoordinator。默认情况下可能不会安装其他版本的服务器。需要先安装Windows功能。(2)在服务器管理工??具AdministrativeTools中找到ComponentServices,在LocalDTC的属性Security选项卡中配置如下,打开相关安全设置,完成后重启服务。也有文档说需要重启服务器,不过至少2012R2没有。(3)配置防火墙,Inbound和Outbound都打开。3、数据库字段text和ntext的处理在表TableA中,有一个ntext类型的Content字段。同步到TableB时,需要对内容进行一些替换处理。text和ntext类型是过时的类型。Microsoft官方建议将它们替换为(N)VARCHAR(MAX),可在此处找到。可以在以后的设计中考虑,这里考虑处理ntext。但是在trigger中inserted和deleted表是不允许处理text/ntext/image类型的。这里我们使用曲线救国,从数据库中读取记录到临时表中,然后使用textptr和patindex函数以及updatetext命令完成字符串替换过程ifexists(select*fromtempdb..sysobjectswhereid=object_id('tempdb..#temp_tablea'))droptable#temp_tableaselect*into#temp_tableafromTableAwhereID=@IDdeclare@svarchar(200),@dvarchar(200)select@s='/_target/',@d='/_replacement/'declare@pvarbinary(16),@postionint,@lintselect@p=textptr(Content),@l=len(@s),@postion=patindex('%'+@s+'%',Content)-1from#temp_tableawhile@postion>0beginupdatetext#temp_tablea.Content@p@postion@l@dselect@postion=patindex('%'+@s+'%',Content)-1from#temp_tablea特别注意上面代码中的text类型,会出问题处理中文的时候。由于文本存储非unicode数据,patindex将汉字解释为1个字符,但updatetext命令将汉字解释为2个字符。人物。SQLServer2005及以上版本可以这样替换:update#temp_tableasetContent=cast(replace(cast(Contentasnvarchar(max)),@s,@d)astext)4.进行远程数据库操作在配置链接服务器时,我们可以直接access远程数据库表如下:insertintoLNK_ServerB_DatabaseB.DatabaseB.dbo.TableB...updateLNK_ServerB_DatabaseB.DatabaseB.dbo.TableBset...但是简单的SQL编辑器经常报语法错误。另外,为了编程的方便,我们希望通过使用execsp_executesql获得更多的灵活性。其实exec可以直接执行sql语句,但是如果有返回值就比较难了。如下,sp_executesql存储过程通过ID从远程服务器查询表TableB并返回Name后,可以使用output关键字定义变量为返回变量,其中@Nameoutput为返回变量,@ID为传入变量。declare@sqlnvarchar(500),@Namenvarchar(50),@IDnvarchar(40)set@SQL=N'select@Name=NamefromLNK_ServerB_DatabaseB.DatabaseB.dbo.TableBwhereID=@ID'execsp_executesql@SQL,N'@Namenvarchar(50)output,@IDnvarchar(40)',@Nameoutput,@ID另外,exec直接执行sql语句,本质上是执行拼接后的sql字符串。有时将变量拼接成字符串要困难得多(需要多少个单引号?),而sp_executesql就清楚多了declare@SQLnvarchar(500),@Namenvarchar(50),@Countint,@IDnvarchar(40)set@Name=N'Cat'set@Count=0set@ID=N'{00000000-0000-0000-0000-000000000000}'set@SQL=N'updateTableAsetName='''+@Name+''',Count='+@Count+'whereID='''+@ID+''''exec(@SQL)set@SQL=N'updateTableAsetName=@Name,Count=@CountwhereID=@ID'execsp_executesql@SQL,N'@Namenvarchar(50),@Countint,@IDnvarchar(40)',@Name,@Count,@ID