Transactional Replication2:在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中,How Changes Are Propagated for Transactional Articles?

默认的是使用系统自动生成的存储过程来更新(delete,update,insert)数据的。

transactional replication should script out and subsequently call a stored procedure to propagate changes to Subscribers (the default).

By default, transactional replication propagates changes to Subscribers through a set of stored procedures that are installed on each Subscriber. When an insert, update or delete occurs on a table at the Publisher, the operation is translated into a call to a stored procedure at the Subscriber. The stored procedure accepts parameters that map to the columns in the table, allowing those columns to be changed at the Subscriber.

 

二,使用 Default stored procedures 更新数据

The three procedures that replication creates by default for each table article are:

  • sp_MSins_< tablename >, which handles inserts.

  • sp_MSupd_< tablename >, which handles updates.

  • sp_MSdel_< tablename >, which handles deletes.

The <tablename> used in the procedure depends on how the article was added to the publication and whether the subscription database contains a table of the same name with a different owner.

例如,在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 data command 使用 PK column作为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 
复制代码

These  commands ensure that if there is no matching record then error 20598 must be raised. "if @@microsoftversion>0x07320000" verifies that you are using a version of SQL Server above SQL 7.

if @@rowcount = 0 
  if  @@microsoftversion>0x07320000 
    exec sp_MSreplraiserror 20598 

2,示例分析,在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
复制代码

3,查看dbo.sp_MSupd_dbodt_study的源代码

使用@bitmap参数check是否更新主键,@pkc1 是主键列的值。update data command 使用 PK column作为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 command报错。

复制代码
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端数据的非主键属性

1,查看Publisher和Subscriber data snapshot

Publisher Data Snapshot

subscriber Data Snapshot

2, 在Publisher 端insert数据

复制代码
insert into dbo.dt_study
(
ID,
name,
sex
)
values(5,'abc',0)
复制代码

在Subscriber端查看数据更新

3, 在Publisher 端更新数据

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

在Subscriber端查看数据更新

在Subscriber端update数据

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

在Publisher 端更新数据

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

在Subscriber端查看数据更新

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

 

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

1,在Subscriber端删除ID=5的记录

delete dbo.dt_study
where id=5

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

delete dbo.dt_study
where id>=5

3,subscriber Data Snapshot如下,subscriber数据不会更新,数据同步失败。

 

4,查看 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)

5,WorkAround:在Subscriber 端中将缺失的Row PK 补上即可。

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

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

Transaction 何时从Distribution database中移除?

Transaction commands are stored in the distribution database until they are propagated to all Subscribers or until the maximum distribution retention period has been reached. Subscribers receive transactions in the same order in which they were applied at the Publisher.

作者悦光阴
本文版权归作者和博客园所有,欢迎转载,但未经作者同意,必须保留此段声明,且在文章页面醒目位置显示原文连接,否则保留追究法律责任的权利。
分类: Replication






本文转自悦光阴博客园博客,原文链接:http://www.cnblogs.com/ljhdo/p/5050979.html,如需转载请自行联系原作者
目录
相关文章
|
5月前
|
安全 区块链
shard blob transaction是什么
文章讨论了Rollup技术中数据可用性(DA)的概念,解释了为什么Rollup需要将数据上传到Layer1,并介绍了EIP-4844引入的shard blob transaction,这是一种为Rollup设计的新型交易,具有数据不可被合约访问和有保存期限的特点。
42 0
|
2月前
|
关系型数据库 MySQL 数据处理
MySQL函数与约束
MySQL 提供了丰富的函数和强大的约束机制,用于数据处理和完整性维护。通过掌握这些工具,可以有效地管理和分析数据库中的数据,确保数据的一致性和准确性。无论是在日常数据查询中使用内置函数,还是在数据库设计中应用各种约束,都是确保数据库系统稳定、高效运行的关键。希望本文对您理解和应用 MySQL 函数与约束有所帮助。
44 1
|
8月前
|
监控 数据库
在Seata中一张表使用了联合主键,在事务回滚时报异常,改为单个主键,就没有这个异常,如何解决?
在Seata中一张表使用了联合主键,在事务回滚时报异常,改为单个主键,就没有这个异常,如何解决?
|
Oracle Java 关系型数据库
oracle实现主键自增长及自动生成策略
oracle实现主键自增长及自动生成策略
419 0
|
SQL 关系型数据库 MySQL
列的完整性约束——设置表字段的外键约束(FOREIGN KEY,FK)
列的完整性约束——设置表字段的外键约束(FOREIGN KEY,FK)
|
算法 Scala 数据库
4. 分库分表之后, id 主键如何处理?
4. 分库分表之后, id 主键如何处理?
127 0
4. 分库分表之后, id 主键如何处理?
|
关系型数据库 Java 数据库
使用jpa在postgresql数据库中创建主键自增表
jpa依赖 org.springframework.boot spring-boot-starter-data-jpa org.
3415 0
jpa @onetomany 级联查询时会有重复数据,去重问题
自己是直接查出来然后利用set去重(自己感觉不是太好,不过能达到目的) List list = query.getResultList();Set set=new HashSet(list);如有更好的方法,希望大佬留言,谢谢
2101 0
只读的表
只读的表
69 0
|
弹性计算 关系型数据库 测试技术
PostgreSQL 分区表如何支持多列唯一约束 - 枚举、hash哈希 分区, 多列唯一, insert into on conflict, update, upsert, merge insert
标签 PostgreSQL , 分区表 , native partition , 唯一 , 非分区键唯一 , 组合唯一 , insert into on conflict , upsert , merge insert 背景 PG 11开始支持HASH分区,10的分区如果要支持hash分区,可以通过枚举绕道实现。 《PostgreSQL 9.x, 10, 11 hash分区表 用法举例
3160 0