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數(shù)據(jù)的主鍵,否則,某些數(shù)據(jù)更新操作會失敗。
一,事務復制中修改是如何傳遞的
在Transactional Replication中,默認情況下,調用系統(tǒng)自動生成的存儲過程來更新(delete,update,insert)訂閱服務器的數(shù)據(jù)。
默認情況下,事務復制通過每個訂閱服務器上的一組存儲過程把更改同步到訂閱服務器。 當在發(fā)布服務器上的表上發(fā)生插入,更新或刪除操作時,該操作將轉換為對訂閱服務器上的存儲過程的調用。 存儲過程接受映射到表中列的參數(shù),從而更新在訂閱服務器上上的列。
二,使用參數(shù)化的存儲過程更新數(shù)據(jù)
對于表來說,默認情況下,會創(chuàng)建三個存儲過程:
sp_MSins_< tablename >,用于處理數(shù)據(jù)插入
sp_MSupd_< tablename >,用于處理Update命令
sp_MSdel_< tablename >,用于處理數(shù)據(jù)刪除
例如,在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每次執(zhí)行時必須保證update,insert或update的數(shù)據(jù)行數(shù)是1,如果更新的記錄數(shù)量不是1,那么Replication報錯。用于Publication的Table必須創(chuàng)建PK,PK起到唯一標識一條記錄的作用。
1,查看 dbo.sp_MSdel_dbodt_study 的源代碼
刪除數(shù)據(jù)時 使用主鍵列作為Delete 命令的過濾條件(Filter condition),保證只刪除一條記錄,如果刪除的數(shù)據(jù)行數(shù)為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端有如下數(shù)據(jù)
如果在Publisher端使用如下腳本,刪除所有的4個記錄
delete dbo.dt_study_publication
那么在Subscriber端,等價的操作是在一個transaction中調用4次dbo.sp_MSdel_dbodt_study,如果在Subscriber端,數(shù)據(jù)有丟失,比如,PKColumn=4 的Record不存在,那么則會導致整個transactino失敗,導致數(shù)據(jù)同步失敗。
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參數(shù)check是否更新主鍵,@pkc1 是主鍵列的值。更新數(shù)據(jù)使用主鍵列作為update命令的Filter condition,保證每次只更新一條記錄,如果更新的數(shù)據(jù)行數(shù)為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] 的源代碼
每次插入一條數(shù)據(jù),如果插入失敗,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端數(shù)據(jù)的非主鍵屬性
查看發(fā)布者和訂閱者中的表dt_study中的數(shù)據(jù):
step1, 在Publisher 端更新數(shù)據(jù)
update dbo.dt_study
set name='update5'
where id=5
在Subscriber端查看數(shù)據(jù)更新
step2,在Subscriber端update數(shù)據(jù)
update dbo.dt_study
set name='update6'
where id=5
step3,在Publisher 端更新數(shù)據(jù)
update dbo.dt_study
set name='update7'
where id=5
step4,在Subscriber端查看數(shù)據(jù)更新
可以看出,如果在Subscriber端對數(shù)據(jù)的非主鍵屬性進行更新,那么不影響transaction replication同步數(shù)據(jù)。
四,更新Subscriber端數(shù)據(jù)的主鍵屬性
把訂閱者中的主鍵更新了,這回導致更新失敗。
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,檢查復制的狀態(tài)
查看 Replication Monitor,在Distributor To Subscriber History Tab 發(fā)現(xiàn)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中移除?
對于執(zhí)行失敗Transaction和commands,Replication不會將其從Distribution database中移除,Distributor Agent 會多次重新執(zhí)行失敗的Transaction。
事務中的命令存儲在distribution數(shù)據(jù)庫中,直到被傳播到訂閱者,或者超過了分發(fā)留存的最大時間。
總結
以上是生活随笔為你收集整理的Transactional Replication2:在Subscriber中,主键列是只读的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 的NodeJS异步数据库函数需要同步的答
- 下一篇: vi/vim使用进阶: 在VIM中使用G