最近给客户做了基于SQLServer的发布订阅的“读写分离”功能,但是某些表数据很大,经常发生某几条数据丢失的问题,导致订阅无法继续进行。但是每次发现问题重新做一次发布订阅又非常消耗时间,所以还得根据“复制监视器”的提示,找到丢失的数据,手工处理。
首先,找到出问题的同步语句,在发布服务器的“复制监视器”上事务订阅的详细信息里面,找到出错的信息
尝试的命令:if @@trancount > rollback tran(事务序列号: 0x0000992600000D09007F00000000,命令 ID: 19) 错误消息: 应用复制的命令时在订阅服务器上找不到该行。 (源: MSSQLServer,错误号: 20598) 获取帮助: http://help/20598应用复制的命令时在订阅服务器上找不到该行。 (源: MSSQLServer,错误号: 20598)
然后在分发服务器上执行下面的SQL语句,
use distributiongosp_browsereplcmds '0x0000992600000D09007F00000000' ,'0x0000992600000D09007F00000000'go
根据命令ID(如上面的ID:19),找到具体的同步命令(Command列),类似于这样的:
{CALL [dbo].[sp_MSdel_dboT_FFTODO] ('697e7cacf5354a36be1ae4cf50dcdaa6')}这里是 订阅库上的 sp_MSdel_dboT_FFTODO 存储过程,查看存储过程定义知道参数是ID的值,这里说找不到要删除的数据,那么我们在订阅库里面模拟增加这个ID的记录即可。添加数据,
网上提供的解决方案是用一个工具生成差异的SQL数据然后给订阅库执行,但看了下觉得不是很方便,想起来SqlServer还提供一个 insert...from....语句,那么是否可以直接从发布数据库查询数据然后插入给订阅数据库呢?
可以使用同义词从发布库查询过来插入到本地订阅库,请看下面具体过程:
先在订阅库上建立一个同义词,比如下面为表 Biz_Customer 建立一个同义词 Biz_Customer_Master,建立的时候,要求指定同义词所在的服务器名称,数据库名称,架构,表名称等信息。

但是此时同义词还不能直接使用,还需要建立“链接服务器”,具体过程如下:
EXEC sp_addlinkedserver @server='192.168.7.4',--被访问的服务器别名(习惯上直接使用目标服务器IP,或取个别名如:JOY) @srvproduct='', @provider='SQLOLEDB', @datasrc='192.168.7.4' --要访问的服务器 go EXEC sp_addlinkedsrvlogin '192.168.7.4', --被访问的服务器别名(如果上面sp_addlinkedserver中使用别名JOY,则这里也是JOY) 'false', NULL, 'sa', --帐号 '1234567890' --密码goselect * from sys.servers;
然后使用下面的SQL语句插入数据:
insert into [Biz_Customer] select * from Biz_Customer_Master where id='7B210173-7382-43EB-BC5E-0000C3BA564A'
查询报错,某个列的数据类型错误,打开表一看,原来是 发布库上的表的字段顺序跟订阅库上不一样,因为当初做订阅的时候,为了解决Timestamp 问题,将订阅库的Timestamp字段修改成了binary(8)类型,故订阅库上表的字段顺序改变了。
此时,只需要在insert 和 select 语句上,指定相同顺序的列就可以了。那么如何获取表所有的列名称?
很简单,直接选择某个表,新建查询,生成的SQL语句就包含表所有的字段了。
最后正确的语句如下:
insert into [Biz_Customer]([Id] ,[CustomerId] ,[Code] ,[Name] ,[BusinessId] ,[CreatedOn] ,[CreatedById] ,[ModifiedOn] ,[ModifiedById] ,[AppraiseTableType] ,[Timestamp] )SELECT [Id] ,[CustomerId] ,[Code] ,[Name] ,[BusinessId] ,[CreatedOn] ,[CreatedById] ,[ModifiedOn] ,[ModifiedById] ,[AppraiseTableType] ,[Timestamp] FROM dbo.Biz_Customer_Master where id='7B210173-7382-43EB-BC5E-0000C3BA564A';
经过这样的方式,很方便的把发布库的数据就补充到订阅库上了,之后,数据库的发布订阅错误就解决了。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3135739/ ,如需转载,请注明出处,否则将追究法律责任。