在使用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数据库中,直到被传播到订阅者,或者超过了分发留存的最大时间。

Transactional Replication2:在Subscriber中,主键列是只读的的更多相关文章

  1. Replication:事务复制 Subscriber的主键列是只读的

    在使用Transactional Replication时,Subscriber 被认为是“Read-Only”的 , All data at the Subscriber is “read-only ...

  2. sql server中主键列的插入问题

    仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'dbo.t_test'中的标识列指定显式值. SET IDENTITY_INSERT dbo.t_test ON ,'c' ...

  3. SQLServer 自增主键创建, 指定自增主键列值插入数据,插入主键

    http://blog.csdn.net/zh2qiang/article/details/5323981 SQLServer 中含自增主键的表,通常不能直接指定ID值插入,可以采用以下方法插入. 1 ...

  4. MyBatis面对Oracle数据库如何实现主键列自增长

    因为Oracle数据库而言 不能够像SqlServer和MySql一样主键自增 而且MyBatis也没有提供直接的主键自增方法 所以我们自己使用查询语句来实现自增 实现代码: <insert i ...

  5. mysql insert插入时实现如果数据表中主键重复则更新,没有重复则插入的四种方法

    [CSDN下载] Powerdesigner 设计主键code不能重复等问题 [CSDN博客] Oracle中用一个序列给两个表创建主键自增功能的后果 [CSDN博客] MySQL自增主键删除后重复问 ...

  6. jqgrid 主键列的设定

    1.如果需要对jqgrid表格数据有互动操作,需要设定主键列. 2.主键列的作用为:在进行jqgrid表格数据交互(编辑.新增.删除行)时,是通过主键列的值来作为引导值来的. 3.注意:不要给一个jq ...

  7. Oracle数据库查询表信息/列信息(列ID/列名/数据类型/长度/精度/是否可以为null/默认值/是否自增/是否是主键/列描述)

    查询表信息(表名/表描述) Select table_Name As Name,Comments As Value From User_Tab_Comments Where table_Type='T ...

  8. cassandra表中主键的类型

    cassandra表中主键的类型及区分? 一.类型及区分 二.参考文章 一.类型及区分 Cassandra的4种Key Primary Key 主键 Composite Key,Compound Ke ...

  9. 根据oracle的主键列生成SQLserver的主键

    根据oracle的主键列生成MsSQLServer的主键列 select 'alter table  ' || cu.table_name ||'  add constraint  '||' PK_' ...

随机推荐

  1. EF DbContext 并发执行时可能出现的问题

    现在许多Web项目都使用了IOC的DI注入组件.其中对象的生命周期管理是非常重要的. 有时我们为了提高请求的响应,经常在请求线程中执行多个子线程,然而忽略了EF的DbContext的生命周期管理. D ...

  2. bzoj3680模拟退火

    看题意就是一道数学物理题,带权费马点   --这怎么是数学了,这也是物理的 所以要用物理方法,比如FFF 国际著名oi选手miaom曾说 模拟退火初温可以低,但是最好烧个几千次 国际著名物理课代表+1 ...

  3. bzoj1503郁闷的出(cheng)纳(xu)员

    好痛苦,,,WA了不知道多少遍 错的服了,,, 如果某员工的初始工资低于工资下界,他将立刻离开公司 我也不知道是我语文有问题还是题目有毒,反正这个东西好像不应该算在离开公司的总人数的答案里... 让我 ...

  4. display:none与visible:hidden的区别

    display:none和visible:hidden都能把网页上某个元素隐藏起来,但两者有区别: display:none ---不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就 ...

  5. Android系列:res之shape制作

    大家好,pls call me francis. nice to me you. 本文将介绍使用在Android中使用shape标签绘制drawable资源图片. 下面的代码是shap标签的基本使用情 ...

  6. 在一定[min,max]区间,生成n个不重复的随机数的封装函数

    引:生成一个[min,max]区间的一个随机数,随机数生成相关问题参考→链接 var ran=parseInt(Math.random()*(max-min+1)+min); //生成一个[min,m ...

  7. mysql单列去重复group by分组取每组前几条记录加order by排序

    mysql分组取每组前几条记录(排名) 附group by与order by的研究,需要的朋友可以参考下 --按某一字段分组取最大(小)值所在行的数据 复制代码代码如下: /* 数据如下: name ...

  8. 前端页面开发,最低兼容IE 8的多设备跨平台问题解决!

    项目要求: 网站能够使用PC.ipad.mobile phone正常访问 页面PSD版式宽度分别为1024px和750px 参考资料 使用CSS3 Media Queries,其作用就是允许添加表达式 ...

  9. hdu 2037简单贪心--活动安排问题

    活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子.该问题要求高效地安排一系列争用某一公共资源的活动.贪心算法提供了一个简单.漂亮的方法使得尽可能多的活动 ...

  10. Python之路【第三篇】python基础 之基本数据类型 补充

    字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-310 ...