SqlServer 禁止架构更改的复制中手动修复使在发布和订阅中分别增加字段同步

由于之前的需要,禁止了复制架构更改,以至在发布中添加一个字段,并不会同步到订阅中,而现在又在订阅中添加了一个同名字段,怎么使这发布和订阅的两个字段建立同步关系呢?

下面就测试更改:此次发布类型为事务复制的可更新订阅,其他类型的发布没有测试。

首先建立事务复制的可更新订阅,建立好之后。

在发布创建一张测试表:

CREATE TABLE [dbo].[DemoTab](
	[Guid] [uniqueidentifier] NOT NULL,
	[SID] [varbinary](85) NOT NULL,
	[Title] [nvarchar](100) NOT NULL,
	CONSTRAINT [PK_DemoTab] PRIMARY KEY CLUSTERED ([SID] ASC,[Guid] ASC)
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DemoTab] ADD  CONSTRAINT [DF_DemoTab_Guid]  DEFAULT (newsequentialid()) FOR [Guid]
GO
ALTER TABLE [dbo].[DemoTab] ADD  CONSTRAINT [DF_DemoTab_SID]  DEFAULT (suser_sid()) FOR [SID]
GO

将表添加发布,并初始化该表:

Exec sp_addarticle
  @publication = 'publication'
, @article = N'DemoTab'
, @source_object = N'DemoTab'
, @source_owner = N'dbo'
, @schema_option = 0x0000000008037CDF
, @vertical_partition = N'true'
GO
Exec sp_refreshsubscriptions 'publication'
GO
Exec sp_startpublication_snapshot 'publication'
GO

分表在发布和订阅都测试,确认同步正常:

INSERT INTO [DemoTab](Guid,SID,Title) select NEWID(),SUSER_SID(),'test'
UPDATE [DemoTab] SET Title = 'KK'
DELETE FROM [DemoTab]

现在禁用 "复制架构更改"

也可以用脚本禁止:

--	禁止 "复制架构更改"
EXEC sp_changepublication @publication = N'publication', @property = N'replicate_ddl', @value = 0

现在分别在发布数据库和订阅数据库执行增加字段,因为架构不同步,所以并不会冲突。

ALTER TABLE dbo.[DemoTab] ADD TEST INT NULL

增加后,只要不对新增的列 test 操作,复制仍正常。但要禁止客户对该表进行操作,因为更改过程中涉及的对象要更改,别面出错!

首先介绍主要参考的3个存储过程,都在发布数据库执行.(注:可执行查看,但生成的脚本不要执行)

--订阅的所有同步存储过程.生成脚本在订阅库执行
EXEC sp_scriptpublicationcustomprocs N'publication'

--发布中的冲突表.生成脚本在发布库执行
EXEC sp_scriptsubconflicttable @publication = 'publication', @article = 'DemoTab'

--订阅触发器.生成脚本在订阅库执行
EXEC sp_script_synctran_commands @publication = 'publication', @article = 'DemoTab'

将新增的列添加到发布项目中(在发布数据库执行)

--查看发布列的信息
select name,column_id from sys.columns where object_id=object_id('DemoTab')
select artid from sysarticles where name='DemoTab'
select * from sysarticlecolumns where artid=1044

从上面可以知道,字段 [TEST]  的id=8 , 表 [DemoTab] 的发布项目编号 artid = 1044,当前字段[TEST]并未添加到发布表中,下面将该列添加到发布

insert into sysarticlecolumns select 1044,8,0,0,0

上面的语句执行后,可以在界面中看到该列已经添加进去。

现在执行上面所说的3个存储过程,在发布数据库执行。该存储过程生成订阅的同步存储过程,生成的脚本在订阅数据库执行(手动应用快照)

EXEC sp_scriptpublicationcustomprocs N'publication'
--
-- 来自数据库 'publisherdb'、发布 'publication' 的事务复制自定义过程:
--

----
---- 项目 'DemoTab' 的复制自定义过程:
----

if object_id(N'[sp_MSins_dboDemoTab]', 'P') > 0
drop proc [sp_MSins_dboDemoTab]
go
if object_id(N'dbo.MSreplication_objects') is not null
delete from dbo.MSreplication_objects where object_name = N'sp_MSins_dboDemoTab'
go
create procedure [sp_MSins_dboDemoTab]
  @c1 uniqueidentifier,@c2 varbinary(85),@c3 nvarchar(100),@c4 uniqueidentifier,@c5 int
as
begin
if not exists (select * from [dbo].[DemoTab]
 where  ( [SID] = @c2 and [Guid] = @c1 )
)
begin
insert into [dbo].[DemoTab](
 [Guid]
,[SID]
,[Title]
,[msrepl_tran_version]
,[TEST]
 )
values (
 @c1
,@c2
,@c3
,@c4
,@c5
 )
end
end
go
if columnproperty(object_id(N'dbo.MSreplication_objects'), N'article', 'AllowsNull') is not null
exec ('insert dbo.MSreplication_objects (object_name, publisher, publisher_db, publication, article, object_type)
 values (+ N''sp_MSins_dboDemoTab'' , N''SZ1CARD1-DB'' , N''PlatformSync'' , N''publication'' , N''DemoTab'' ,''P'')')
go

if object_id(N'[sp_MSupd_dboDemoTab]', 'P') > 0
drop proc [sp_MSupd_dboDemoTab]
go
if object_id(N'dbo.MSreplication_objects') is not null
delete from dbo.MSreplication_objects where object_name = N'sp_MSupd_dboDemoTab'
go
create procedure [sp_MSupd_dboDemoTab]
 @c1 uniqueidentifier,@c2 varbinary(85),@c3 nvarchar(100),@c4 uniqueidentifier,@c5 int,@pkc1 uniqueidentifier,@pkc2 varbinary(85)
,@old_msrepl_tran_version uniqueidentifier
,@bitmap binary(1)
as
begin
if ( substring(@bitmap,1,1) & 1 = 1 or substring(@bitmap,1,1) & 2 = 2 )
begin
update [dbo].[DemoTab] set
 [Guid] = case substring(@bitmap,1,1) & 1 when 1 then @c1 else [Guid] end
,[SID] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [SID] end
,[Title] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [Title] end
,[msrepl_tran_version] = case substring(@bitmap,1,1) & 8 when 8 then @c4 else [msrepl_tran_version] end
,[TEST] = case substring(@bitmap,1,1) & 16 when 16 then @c5 else [TEST] end
where [Guid] = @pkc1 and [SID] = @pkc2
 and msrepl_tran_version = @old_msrepl_tran_version
end
else
begin
update [dbo].[DemoTab] set
 [Title] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [Title] end
,[msrepl_tran_version] = case substring(@bitmap,1,1) & 8 when 8 then @c4 else [msrepl_tran_version] end
,[TEST] = case substring(@bitmap,1,1) & 16 when 16 then @c5 else [TEST] end
where [Guid] = @pkc1 and [SID] = @pkc2
 and msrepl_tran_version = @old_msrepl_tran_version
end
end
go
if columnproperty(object_id(N'dbo.MSreplication_objects'), N'article', 'AllowsNull') is not null
exec ('insert dbo.MSreplication_objects (object_name, publisher, publisher_db, publication, article, object_type)
values (+ N''sp_MSupd_dboDemoTab'' , N''SZ1CARD1-DB'' , N''PlatformSync'' , N''publication'' , N''DemoTab'' ,''P'')')
go

if object_id(N'[sp_MSdel_dboDemoTab]', 'P') > 0
drop proc [sp_MSdel_dboDemoTab]
go
if object_id(N'dbo.MSreplication_objects') is not null
delete from dbo.MSreplication_objects where object_name = N'sp_MSdel_dboDemoTab'
go
create procedure [sp_MSdel_dboDemoTab]
  @pkc1 uniqueidentifier,@pkc2 varbinary(85)
,@msrepl_tran_version uniqueidentifier
as
begin
delete [dbo].[DemoTab]
where [Guid] = @pkc1 and [SID] = @pkc2
 and msrepl_tran_version = @msrepl_tran_version
end
go
if columnproperty(object_id(N'dbo.MSreplication_objects'), N'article', 'AllowsNull') is not null
exec ('insert dbo.MSreplication_objects (object_name, publisher, publisher_db, publication, article, object_type)
values (+ N''sp_MSdel_dboDemoTab'' , N''SZ1CARD1-DB'' , N''PlatformSync'' , N''publication'' , N''DemoTab'' ,''P'')')
go

此存储过程生成应用于订阅的跟踪项目信息和同步触发器。 生成的脚本在订阅服务器的订阅数据库上执行。 此存储过程在发布服务器的发布数据库中执行。

EXEC sp_script_synctran_commands @publication = 'publication', @article = 'DemoTab'

if @@microsoftversion<0x07320000
raiserror('当发布服务器为 SQL Server 2000 或更高版本时,必须将订阅服务器升级到 SQL Server 2000 才能创建可更新订阅。',16, -1)

if (@@microsoftversion >= 0x09000000)
begin
	exec sp_addqueued_artinfo 1044
	, N'DemoTab'
	, N'publisher'
	, N'publicationDB'
	, N'publication'
	, N'DemoTab'
	, N'dbo'
	, N'conflict_publication_DemoTab'
end 

if (@@microsoftversion < 0x09000000)
begin
	exec sp_addqueued_artinfo 1044
	, N'DemoTab'
	, N'publisher'
	, N'publicationDB'
	, N'publication'
	, N'DemoTab'
	, N'dbo'
	, N'conflict_publication_DemoTab'
	, 0x000000000000000000000000000000000000000000000000000000000000008f
end 

if (@@microsoftversion >= 0x09000000)
begin
	delete from MSsubscription_articlecolumns
	where artid = 1044
	and agent_id = (
		select id from MSsubscription_agents
		where update_mode > 0
		and UPPER(publisher) = UPPER(N'publisher')
		and publisher_db = N'publicationDB'
		and publication = N'publication'
	)
end 

if (@@microsoftversion >= 0x09000000)
begin
	declare @agent_id_1044 int
	select @agent_id_1044 = id
	from MSsubscription_agents
	where update_mode > 0
	and UPPER(publisher) = UPPER(N'publisher')
	and publisher_db = N'publicationDB'
	and publication = N'publication' 

	if @agent_id_1044 is not null
	begin
		insert MSsubscription_articlecolumns (agent_id, artid, colid)
		values (@agent_id_1044, 1044, 1)
		insert MSsubscription_articlecolumns (agent_id, artid, colid)
		values (@agent_id_1044, 1044, 2)
		insert MSsubscription_articlecolumns (agent_id, artid, colid)
		values (@agent_id_1044, 1044, 3)
		insert MSsubscription_articlecolumns (agent_id, artid, colid)
		values (@agent_id_1044, 1044, 4)
		insert MSsubscription_articlecolumns (agent_id, artid, colid)
		values (@agent_id_1044, 1044, 8)
	end
end 

if (@@microsoftversion >= 0x080002C0)
begin
	exec sp_addsynctriggers
	 N'DemoTab'
	, N'dbo'
	, N'publisher'
	, N'publicationDB'
	, N'publication'
	, N'sp_MSsync_ins_DemoTab_4'
	, N'sp_MSsync_upd_DemoTab_4'
	, N'sp_MSsync_del_DemoTab_4'
	, N'sp_MScft_publication_DemoTab'
	, N'dbo'
	, N'null'
	, N'null'
	, N'null'
	, 0x03
	, 0
	,1
	,N'publisher'
	, 2
end 

if (@@microsoftversion < 0x080002C0)
begin
	exec sp_addsynctriggers
	 N'DemoTab'
	, N'dbo'
	, N'publisher'
	, N'publicationDB'
	, N'publication'
	, N'sp_MSsync_ins_DemoTab_4'
	, N'sp_MSsync_upd_DemoTab_4'
	, N'sp_MSsync_del_DemoTab_4'
	, N'sp_MScft_publication_DemoTab'
	, N'dbo'
	, N'null'
	, N'null'
	, N'null'
	, 0x03
	, 0
	,1
	,N'publisher'
end

订阅相关对象已经更改完成!接下来还得改发布中的一些对象!~

查看发布数据库中涉及的对象:

SELECT * FROM sysarticleupdates WHERE artid=(select artid from sysarticles where name='DemoTab')

对应d 对象,这些对象都需要更改!~

select
case
	when object_id=427877337 then 'sync_ins_proc'
	when object_id=443877394 then 'sync_upd_proc'
	when object_id=459877451 then 'sync_del_proc'
	when object_id=475877508 then 'sync_upd_tri'
	when object_id=491877565 then 'conflict_tableid'
	when object_id=539877736 then 'ins_conflict_proc'
	else '' end as sysarticleupdates
,object_id,name
from sys.objects
where object_id in(427877337,443877394,459877451,475877508,491877565,539877736)

6 个对象,将逐个更改!(sp_MSsync_upd_trig_DemoTab_4 不需要更改)

1. 更改冲突表 conflict_publication_DemoTab

重新创建冲突表.在发布数据库执行,生成的脚本在发布数据库执行.

EXEC sp_scriptsubconflicttable @publication = 'publication', @article = 'DemoTab'
if object_id(N'[dbo].[conflict_publication_DemoTab]') is not null
begin DROP TABLE [dbo].[conflict_publication_DemoTab] end
CREATE TABLE [dbo].[conflict_publication_DemoTab](
    [Guid] uniqueidentifier NOT NULL
    ,[SID] varbinary(85) NOT NULL
    ,[Title] nvarchar(100) NOT NULL
    ,[msrepl_tran_version] uniqueidentifier NOT NULL
    ,[TEST] int NULL
	,origin_datasource nvarchar(255) NULL
	,conflict_type int NULL
	,reason_code int NULL
	,reason_text nvarchar(720) NULL
	,pubid int NULL
	,tranid nvarchar(40) NULL
	,insertdate datetime NOT NULL
	,qcfttabrowid uniqueidentifier DEFAULT NEWID() NOT NULL
)
CREATE UNIQUE INDEX [cftind_publication_DemoTab]
ON [dbo].[conflict_publication_DemoTab]([SID], [Guid], tranid, qcfttabrowid)

重建表之后,object_id 不一样,sysarticleupdates 的冲突表id需要更改。

update sysarticleupdates
set conflict_tableid = (select object_id from sys.objects where object_id=object_id('conflict_publication_DemoTab'))
where artid=(select artid from sysarticles where name='DemoTab')

2.修改更新冲突表的存储过程

exec sp_helptext sp_MScft_publication_DemoTab

3. 更改发布中的存储过程

发布库这 3 个存储过程:sp_MSsync_del_DemoTab_4,sp_MSsync_ins_DemoTab_4,sp_MSsync_upd_DemoTab_4

这3 个存储过程分别被订阅数据库表的触发器调用,因此注意传参的位置.新字段[test]参数在[msrepl_tran_version]之后

trg_MSsync_del_DemoTab 调用存储过程 sp_MSsync_del_DemoTab_4

trg_MSsync_ins_DemoTab 调用存储过程 sp_MSsync_ins_DemoTab_4

trg_MSsync_upd_DemoTab 调用存储过程 sp_MSsync_upd_DemoTab_4

这3个存储改动的地方较多,但是都是更改相应的列。里面要加入参数,或者字段赋值等,字段test参考其他字段就行,参数只是改变个编号。

 [sp_MSsync_del_DemoTab_4]  增加传递的参数 @c5_old  INT ,修改一处位置如下。

[sp_MSsync_ins_DemoTab_4] 增加传递的参数 @c5  INT 

更改2处相同代码:

    insert into [dbo].[DemoTab](  [Guid] , [SID] , [Title] , [msrepl_tran_version] ,TEST )
    values (  @c1 , @c2 , @c3 , @c4 ,@c5 )  

更改1处代码:

sp_MSsync_upd_DemoTab_4 增加2个参数 @c6 int  ,,@c6_old int  ,更改几处脚本

参数位置参考订阅触发器 trg_MSsync_upd_DemoTab 中传递的位置 :@c1,@c2,@c3,@c4,@c6  ,@c1_old,@c2_old,@c3_old,@c4_old,@c6_old

注: 上面的参数应该都以触发器中的名称编号一样,不是@c5, 而是 @c6 ,避免以后再添加列时导致错乱!~上面的应该改!(刚忘记 了,就不回去改了)

注意这里,前8列获取第一个字节 substring(@bitmap,1,1) ,每列对应一个位,第5列为 00010000, 为16.注意改这里。

(更多参考 深入理解SQL Server 2005 中的 COLUMNS_UPDATED函数 )

发布对象更改完成!~

现在进行测试,分别在发布库和订阅库执行一遍,数据正常同步!~

INSERT INTO [DemoTab](Guid,SID,Title) select NEWID(),SUSER_SID(),'test'
UPDATE [DemoTab] SET Title = 'KK'
DELETE FROM [DemoTab]

INSERT INTO [DemoTab](Guid,SID,Title,test) select NEWID(),SUSER_SID(),'test',0
UPDATE [DemoTab] SET test = 10
DELETE FROM [DemoTab]

ALTER TABLE dbo.[DemoTab] DROP COLUMN TEST 

最终删除该列 【test】,订阅库中也自动同步被删除!~同步正常!~试验结束!~

总结:

手动更改比较麻烦!~尤其是在发布库,没有找到相关自动生成的存储过程(觉得应该是有的),所以发布的对象一个个更改!~刚开始的时候,本人连订阅的对象都是一个个更改!~后来测试几次总结出这个顺序。

--发布库执行,将新增的字段添加到发布.
select name,column_id from sys.columns where object_id=object_id('DemoTab')
select artid from sysarticles where name='DemoTab'
select * from sysarticlecolumns where artid=1044

--发布库执行,生成的脚本在订阅执行.
EXEC sp_scriptpublicationcustomprocs N'publication'
EXEC sp_scriptsubconflicttable @publication = 'publication', @article = 'DemoTab'
EXEC sp_script_synctran_commands @publication = 'publication', @article = 'DemoTab'

--发布库执行,修改发布相关对象
SELECT * FROM sysarticleupdates WHERE artid=

为什么要这样做?有时候有的表没有同步、有时某些对象被删除、或者原本不行同步,现在又同步了(如开始说明)。

这里还没完全测试,比如在发布和订阅的字段都有数据时,会不会也是同样处理?

时间: 2024-11-05 14:52:53

SqlServer 禁止架构更改的复制中手动修复使在发布和订阅中分别增加字段同步的相关文章

git中手动删除的文件如何在git中删除

在日常开发中,我们可能或手动删除(delete键删除的)一些文件,然而我们本来应该是用git rm fileName命令删除的,但是现在我们手动删除了,那么要如何在git里面讲那些手动删除的文件删除呢? 我们这里有两种方法可以在git中删除那些手动删除(delete键删除的)的文件: 第一种就是用 git rm files 删除你手动删除的文件或文件夹. 当然,如果你删除的文件有很多,而且分布在不同的文件夹中,使用第一种 git rm files 的方法,显然不方便,效率也很低下,那么有没有更快

MyEclipse中拷贝J2EE项目,发布到tomcat中名字一样的解决办法

修改Eclipse工作空间下新拷贝项目下.settings文件夹中org.eclipse.wst.common.component的两个属性值. 为新项目名字: <?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">    <wb-module deploy-

SQLServer 可更新订阅数据在线架构更改(增加字段)方案

之前一直查找冲突发布和订阅数据不一致的原因,后来发现多少数据库升级引起,因为一直以来都是在发布数据库增加字段,订阅也会自动同步.在此时如果订阅队列有数据,这些数据将丢失.参考上一篇说明:SQLServer 可更新订阅数据冲突的一个原因 .当在发布数据库增加一个字段时,系统同步存储过程和触发器都会重新生成,这会导致仍在队列中的数据无法正常同步.订阅队列中的命令将因"同步"后消失,代理有可能出错,但也会自动回复正常!~ 这周测试了一些方法,最终算是确定一个方案可行的,虽然麻烦和耗时. 首先

SqlServer Bug:复制架构更改参数(replicate_ddl)无效

最近测试可更新订阅的架构更改问题,发现了一个 bug. 在复制中,当在发布数据库对发布数据库进行架构更改时,结构自动同步到订阅中(这就是 复制架构更改).由于某些原因,对某个表增加字段时,不需要同步到订阅.在发布属性中,有一个选项可以控制不同步架构更改.如下图: 只有将 复制架构更改 的值改为 false ,更改结构则不同步,更改实时生效. 也可以脚本来更改该参数: EXEC sp_changepublication @publication = N'publication', @propert

SQLServer 2005 数据库定阅复制实现双机热备(主要是sharepoint 内容数据库)

原文:SQLServer 2005 数据库定阅复制实现双机热备(主要是sharepoint 内容数据库) 场景 公司最近的sharepoint的数据库服务器老是出问题,并且在一旦出现问题,就导致无法正常工作.最主要的是我们要加班还原以前的数据库,这是最头疼的.于是在网上查找资料,实现主备机的同步,对于sharepoint而言我们只需做到sharepoint的内容数据库同步即可.这种技术有个专业名词叫做双机热备. 双机热备原理 双机热备特指基于高可用系统中的两台服务器的热备(或高可用),因两机高可

iOS-旧项目中手动内存管理(MRC)转ARC

在ARC之前,iOS内存管理无论对资深级还是菜鸟级开发者来说都是一件很头疼的事.我参 加过几个使用手动内存管理的项目,印象最深刻的是一个地图类应用,由于应用本身就非常耗内存,当时为了解决内存泄露问题,每周都安排有人值班用 Instruments挨个跑功能,关键是每次都总能检查出来不少.其实不管是菜鸟级还是资深级开发者都避免不了写出内存泄露的代码,规则大家都懂,可是 天知道什么时候手一抖就少写了个release? 好在项目决定转成ARC了,下面将自己转换的过程和中间遇到的问题写出来和大家共享,希望

在Maven仓库中手动添加Oracle11g JDBC驱动

由于Oracle授权问题,Maven3不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到本地仓库 手动添加oracle 11g JDBC 驱动  mvn install:install-file -Dfile=D:/ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1.0 -Dpackaging=jar 命令执行后 将D:/ojdbc6.

linux中手动释放缓存的方法

linux中手动释放缓存的方法  Linux释放内存的相关知识介绍: 在Linux系统下,我们一般不需要去释放内存,因为系统已经将内存管理的很好.但是凡事也有例外,有的时候内存会被缓存占用掉,导致系统使用SWAP空 间影响性能,例如当你在linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching.,此时就需 要执行释放内存(清理缓存)的操作了. Linux系统的缓存机制是相当先进的,他会针对dentry(用于VFS,加速文件路径名到inode的

MySQL集群架构05分组复制架构和NDB集群架构

本博客讨论MySQL原生的两种架构:分组复制架构和NDB集群架构.这两种架构在之前的博客中有详细介绍. 一.MySQL分组复制架构 1.架构说明 MySQL Group Replication架构总体上还是一种基于复制的技术架构,可以轻松实现单主结构或者多主结构.每份数据存在于2个节点中,提供了数据安全保障的同时,节省了存储空间.主节点对外提供读写服务,而其它从结点仅仅提供只读服务.Group Replication内部实现了自动屏蔽故障主机的功能. 2.核心原理 MySQL Group Rep