zoukankan      html  css  js  c++  java
  • Replication 第四篇:事务复制中Subscriber的主键列是只读的

    在使用Transactional Replication时,Subscriber 被认为是“Read-Only”的 , All data at the Subscriber is “read-only” (transactional replication does not enforce this at the Subscriber),实际上,除了主键列,其他字段是可以修改的。但是不能更新Subscriber数据的主键,否则,某些数据更新操作会失败。

    一,事务复制中修改是如何传递的

    在Transactional Replication中,默认情况下,调用系统自动生成的存储过程来更新(delete,update,insert)订阅服务器的数据。

    默认情况下,事务复制通过每个订阅服务器上的一组存储过程把更改同步到订阅服务器。 当在发布服务器上的表上发生插入,更新或删除操作时,该操作将转换为对订阅服务器上的存储过程的调用。 存储过程接受映射到表中列的参数,从而更新在订阅服务器上上的列。

    二,使用参数化的存储过程更新数据

    对于表来说,默认情况下,会创建三个存储过程:

    • sp_MSins_< tablename >,用于处理数据插入

    • sp_MSupd_< tablename >,用于处理Update命令

    • sp_MSdel_< tablename >,用于处理数据删除

    例如,在Programmability catalog下,有三个sp,分别是:dbo.sp_MSdel_dbodt_study,dbo.sp_MSins_dbodt_study,dbo.sp_MSupd_dbodt_study,用以对subscriber端的 dbo.dt_sutdy进行delete,insert和update 操作,这三个sp每次执行时必须保证update,insert或update的数据行数是1如果更新的记录数量不是1,那么Replication报错。用于Publication的Table必须创建PK,PK起到唯一标识一条记录的作用。

    1,查看 dbo.sp_MSdel_dbodt_study 的源代码

    删除数据时 使用主键列作为Delete 命令的过滤条件(Filter condition),保证只删除一条记录,如果删除的数据行数为0,则报错。

    ALTER procedure [dbo].[sp_MSdel_dbodt_study]
            @pkc1 int
    as
    begin  
        delete [dbo].[dt_study]
        where [id] = @pkc1
    if @@rowcount = 0
        if @@microsoftversion>0x07320000
            exec sp_MSreplraiserror 20598
    end 

    示例分析,在Publisher端有如下数据

    如果在Publisher端使用如下脚本,删除所有的4个记录

    delete dbo.dt_study_publication

    那么在Subscriber端,等价的操作是在一个transaction中调用4次dbo.sp_MSdel_dbodt_study,如果在Subscriber端,数据有丢失,比如,PKColumn=4 的Record不存在,那么则会导致整个transactino失败,导致数据同步失败。

    set XACT_ABORT on
    
    begin tran
        exec dbo.sp_MSdel_dbodt_study @pkc1=1
        exec dbo.sp_MSdel_dbodt_study @pkc1=2
        exec dbo.sp_MSdel_dbodt_study @pkc1=3
        exec dbo.sp_MSdel_dbodt_study @pkc1=4
    commit
    set XACT_ABORT off

    2,查看dbo.sp_MSupd_dbodt_study的源代码

    使用@bitmap参数check是否更新主键,@pkc1 是主键列的值。更新数据使用主键列作为update命令的Filter condition,保证每次只更新一条记录,如果更新的数据行数为0,则报错。

    ALTER procedure [dbo].[sp_MSupd_dbodt_study]
            @c1 int = NULL,
            @c2 nvarchar(50) = NULL,
            @c3 bit = NULL,
            @pkc1 int = NULL,
            @bitmap binary(1)
    as
    begin  
    if (substring(@bitmap,1,1) & 1 = 1)
    begin 
    
    update [dbo].[dt_study] set
            [id] = case substring(@bitmap,1,1) & 1 when 1 then @c1 else [id] end,
            [name] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [name] end,
            [sex] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [sex] end
        where [id] = @pkc1
    if @@rowcount = 0
        if @@microsoftversion>0x07320000
            exec sp_MSreplraiserror 20598
    end  
    else
    begin 
    
    update [dbo].[dt_study] set
            [name] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [name] end,
            [sex] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [sex] end
        where [id] = @pkc1
    if @@rowcount = 0
        if @@microsoftversion>0x07320000
            exec sp_MSreplraiserror 20598
    end 
    end 

    4, 查看 [dbo].[sp_MSins_dbodt_study] 的源代码

    每次插入一条数据,如果插入失败,Insert 命令报错。

    ALTER procedure [dbo].[sp_MSins_dbodt_study]
        @c1 int,
        @c2 nvarchar(50),
        @c3 bit
    as
    begin  
        insert into [dbo].[dt_study](
            [id],
            [name],
            [sex]
        ) values (
        @c1,
        @c2,
        @c3    ) 
    end  

    三,更新Subscriber端数据的非主键属性

    查看发布者和订阅者中的表dt_study中的数据:

    step1, 在Publisher 端更新数据

    update dbo.dt_study 
    set name='update5'
    where id=5

    在Subscriber端查看数据更新

    step2,在Subscriber端update数据

    update dbo.dt_study 
    set name='update6'
    where id=5

    step3,在Publisher 端更新数据

    update dbo.dt_study 
    set name='update7'
    where id=5

    step4,在Subscriber端查看数据更新

    可以看出,如果在Subscriber端对数据的非主键属性进行更新,那么不影响transaction replication同步数据。

    四,更新Subscriber端数据的主键属性

    把订阅者中的主键更新了,这回导致更新失败。

    1,把订阅者中的主键删除

    在Subscriber端删除ID=5的记录

    delete dbo.dt_study
    where id=5

    在Publisher 端删除 dbo.dt_study 中ID>=5的所有记录

    delete dbo.dt_study
    where id>=5

    2,检查复制的状态

    查看 Replication Monitor,在Distributor To Subscriber History Tab 发现Error Message:

    The row was not found at the Subscriber when applying the replicated command. (Source: MSSQLServer, Error number: 20598)

    3,WorkAround

    在Subscriber 端中把缺失的Row 中的主键补上即可,非主键可以随意赋值。

    insert into dbo.dt_study
    (ID,name,sex)
    values(5,null,null)

    4,Transaction 何时从Distribution database中移除?

    对于执行失败Transaction和commands,Replication不会将其从Distribution database中移除,Distributor Agent 会多次重新执行失败的Transaction。

    事务中的命令存储在distribution数据库中,直到被传播到订阅者,或者超过了分发留存的最大时间。

  • 相关阅读:
    Components controls 区别
    lazarus 2016 2月18 4:22:35 支持android开发了, 既ios,linux,macosx,window,web 后 囊括一切啦。 哈哈
    Delphi MlSkin V1.1 发布啦! 它能让你的程序拥有像QQ一样多彩炫丽的外观!
    Tclientdataset的CloneCursor问题 clientdataset 复制 赋值 的问题
    字符串 映射 函数
    字符串 映射相应的 函数 字符串驱动技术—— MethodAddress , MethodName , ObjectInvoke
    一分钟了解nohup和&的功效
    Linux shell标准输入,标准输出,错误输出
    (一)shell编程之执行脚本的三种方式
    Shell:执行脚本文件方法
  • 原文地址:https://www.cnblogs.com/ljhdo/p/5050979.html
Copyright © 2011-2022 走看看