
大多数SQL Server 复制拓扑都是基于中心发布模型,它是由一个发布复制到一个或者多个订阅。另一个复制模型是中心订阅模型,它使用事务复制由多个发布复制到一个订阅中。

图一
默认情况下,订阅通过快照代理初始化生成快照并被分发代理应用。当快照被应用时,默认情况 项目(article)属性 “名称已被使用时的操作(Action if name is in use)" 设置为 "删除先有对象并重新创建(Drop existing object and create a new one)" ,意思是当订阅中存在目标表对象时将被删除,并重新创建该对象。在中心订阅模型中,当从多个发布中应用快照时这种设置是有问题的。第一个快照应用是正常的,后续的快照应用时将会清除掉前一个快照的数据。

图二
CREATE TABLE [dbo].[DemoTab]([id] [int] IDENTITY(1,1) NOT NULL,[name] [varchar](10) NOT NULL,[value] [decimal](18, 4) NULL,CONSTRAINT [PK_DemoTab] PRIMARY KEY CLUSTERED ([id] ASC))
如果这样,id 自增量肯定有重复键,因此增加一个标志列 [LocationID],并如 id 列作为组合键。如下,分别在两个发布数据表中创建表。
--数据库:[TestDBSubA]USE [TestDBSubA]GOCREATE TABLE [dbo].[DemoTab]([id] [int] IDENTITY(1,1) NOT NULL,[name] [varchar](10) NOT NULL,[value] [decimal](18, 4) NULL,[LocationID] INT NOT NULL DEFAULT(1)CONSTRAINT [PK_DemoTab] PRIMARY KEY CLUSTERED ([id] ASC,[LocationID] ASC))--数据库:[TestDBSubB]USE [TestDBSubB]CREATE TABLE [dbo].[DemoTab]([id] [int] IDENTITY(1,1) NOT NULL,[name] [varchar](10) NOT NULL,[value] [decimal](18, 4) NULL,[LocationID] INT NOT NULL DEFAULT(2)CONSTRAINT [PK_DemoTab] PRIMARY KEY CLUSTERED ([id] ASC,[LocationID] ASC))
此时就可以使用字段 [LocationID] 来确定是不同数据库的数据了,在同一个订阅表中就不会有主键重复问题了。但是当在其中一个发布初始化时,或者操作数据时,怎么区分来自不同的发布数据库的数据呢?接下来设置静态行筛选器,非常重要!

图三
下一步,设置行筛选器,筛选条件为 [LocationID]=1(这个是数据库 [TestDBSubA] 的发布),同理设置 [TestDBSubB] 的发布!

图四

图五

图六
选择设置所有表,设置属性 “名称已被使用时的操作”为 “删除数据,如果目标有行筛选器,仅删除与该筛选器匹配的数据(Delete data,If article has a row filter, delete only data that matches the filter)”

图七

图八
先后分别初始化应用快照,正常!

图九
现在测试,分别在两发布数据库中插入数据。
INSERT INTO [TestDBSubA].[dbo].[DemoTab]([name],[value]) SELECT 'TestDBSubA',0INSERT INTO [TestDBSubB].[dbo].[DemoTab]([name],[value]) SELECT 'TestDBSubB',0SELECT * FROM [TestDB].[dbo].[DemoTab]

图十
结果合并了!所有DML操作都能正常同步,但是字段增删改则有问题。中心订阅一般用于固定数据结构的数据同步,或者用于临时的数据迁移。




