网上关于sqlserver基于发布/订阅实现数据同步的文章很多,大多介绍不详细,各种copy。为实现发布服务器、订阅服务器数据库实时同步,近期花了几天时间认真研究了一下,并实践验证通过,希望本文能帮助到有同样需求的朋友们。
(1)发布服务器上新建发布
(2)选择需要发布的数据库,点击下一步
(3)选择事务发布,点击下一步
(4)勾选所有的发布对象,点击下一步
(5)无需筛选发布中数据,直接点击下一步
(6)立即创建快照,点击下一步
(7)安全设置
(8)输入发布SQL Server登录账户和密码,点击确定
(9)点击下一步
(10)创建发布,点击下一步
(11)输入发布名称,点击完成
发布成功后,在本地SQL server管理工具的,复制->本地发布中,可以查看到刚刚发布的数据库。
(1)登录订阅服务器,在订阅服务器中新建订阅
(2)查找发布服务器
(3)查找到刚刚做过发布的服务器,并使用发布服务器的登录名和密码,点击连接
(4)选择刚刚已经发布过的数据库,点击下一步
(5)选择在分发服务器上运行所有代理(推送订阅),点击下一步
(6)添加订阅数据库,点击下一步
(7)配置订阅服务器连接属性
(8)输入发布服务器登录名和密码,点击确定
(9)点击下一步
(10)代理计划是连续运行,点击下一步
(11)初始化时间为立即,点击下一步
(12)创建订阅,点击下一步
(13)完成订阅
完成订阅设置后,在本地SQL server管理工具的,复制->本地订阅中可以查看到刚刚订阅的数据库,以及查看订阅历史记录。
发布/订阅配置成功后,发布服务器数据库中的数据实时同步到订阅服务器数据库, 但发布服务器数据库新增的表并不会自动同步到订阅服务器数据库中。在实际应用中,时常需要新增表、索引,如果采用默认的设置,每次都需要重新初始化快照,从库重新应用快照和未执行的同步命令,从占用网络资源、时间上来说显然不是一种理想的方法。另一种方法是将新增的架构变更新建一个发布订阅,但会造成维护困难,增加出错的几率。
接下来给大家分享一下近期研究的解决办法。
immediate_sync:指定每次运行快照代理时是否为发布创建同步文件。如果为 True,表示每次运行快照代理时都创建或重新创建同步文件。 如果为 False,则仅当有新订阅时,才创建同步文件。 当以增量方式向现有发布添加新项目,必须为每个订阅调用 sp_addsubscription。 订阅后订阅服务器无法接收同步文件,直到启动并完成快照代理为止。
allow_anonymous:指定是否可为给定发布创建匿名订阅。 如果为True,则 immediate_synchronization 也必须设置为 True。 如果为 False,则表示不允许对该发布创建匿名订阅。
查看参数值:
USE DH_DG --DH_DG发布数据库
sp_helppublication;
或者:
select immediate_sync ,allow_anonymous from dbo .syspublications;
修改参数值为0:
use DH_DG ; --DH_DG发布数据库
EXEC sp_changepublication
@publication = ‘DH_DG’, --发布名称
@property = ‘allow_anonymous’ ,
@value = ‘false’
GO
EXEC sp_changepublication
@publication = ‘DH_DG’, --发布名称
@property = ‘immediate_sync’ ,
@value = ‘false’
GO
Job配置如下(注:Job分为2步,步骤1设置“成功时,转到下一步”)
步骤1脚本:
declare @publication varchar(50)
declare @dbName varchar(50)
declare @tableName varchar(100)
declare @sql varchar(max)
set @publication=‘DH_DG’ --发布名称
set @dbName=‘DH_DG’ --数据库名称
–游标遍历数据库中的所有表(含主键且不是系统表的表)
DECLARE GRID_CUR CURSOR FOR
SELECT Name FROM SysObjects Where xtype=‘U’ --xtype=’U’ 表示对象类型为表
and category<> 2 – category = 2系统表
and id in (select parent_obj from SysObjects where xtype=‘PK’ --xtype=‘PK’ 含主键的表) ORDER BY Name
Open GRID_CUR
Fetch Next From GRID_CUR into @tableName
while(@@FETCH_STATUS=0)
begin
set @sql=’’
if not exists (select 1 from dbo.sysarticles where name = @tableName) --没有发布的表
begin
–将新增的表(Article)添加到发布端。
set @sql=‘exec sp_addarticle @publication = N’’’+@publication+’’’,’
set @sql=@sql+’@article = N’’’+@tableName+’’’,’
set @sql=@sql+’@source_owner = N’‘dbo’’,’
set @sql=@sql+’@source_object = N’’’+@tableName+’’’,’
set @sql=@sql+’@type = N’‘logbased’’,’
set @sql=@sql+’@description = null,’
set @sql=@sql+’@creation_script = null,’
set @sql=@sql+’@pre_creation_cmd = N’‘drop’’,’
set @sql=@sql+’@schema_option = 0x000000000803509D,’
set @sql=@sql+’@identityrangemanagementoption = N’‘manual’’,’
set @sql=@sql+’@destination_table = N’’’+@tableName+’’’,’
set @sql=@sql+’@destination_owner = N’‘dbo’’,’
set @sql=@sql+’@vertical_partition = N’‘false’’,’
set @sql=@sql+’@force_invalidate_snapshot = 1,’
set @sql=@sql+’@ins_cmd = N’‘CALL sp_MSins_dbo’++@tableName+’’’,’
set @sql=@sql+’@del_cmd = N’‘CALL sp_MSdel_dbo’++@tableName+’’’,’
set @sql=@sql+’@upd_cmd = N’‘SCALL sp_MSupd_dbo’++@tableName+’’’;’
exec(@sql)
–将新增的表(Article)添加到订阅端。
exec sp_addsubscription @publication=@publication,
@article=@tableName,
@subscriber=‘DTH_DB2’, --订阅服务器机器名
@destination_db=‘DH_DG’, --订阅数据库
@reserved=‘Internal’ –内部保留字段,默认值为‘reserved’,官方帮助文档上似乎也查不到,挺坑的,这里必须设置为‘Internal’,有兴趣的朋友可以去国外网站搜搜。
end
Fetch Next From GRID_CUR into @tableName
end
Close GRID_CUR
deallocate GRID_CUR
步骤2脚本:
if exists (select 1 from dbo.syssubscriptions where dest_db=‘DH_DG’ AND status<>2) --status=2订阅状态为使用中
begin
exec sp_startpublication_snapshot @publication=‘DH_DG’ --发布名称
End
注:以上将新增的表(Article)添加到发布端、订阅端语句执行效率高,占用资源少,我这里设置Job是每分钟执行一次,如对实时性要求更高,可进一步调整作业计划属性设置,无需担心Job影响数据库系统性能。
至此,完美实现发布数据库与订阅数据库数据的实时同步。