適用於:SQL Server
Azure SQL 受控執行個體
異動複寫可讓您指定資料變更從「發行者」傳播到「訂閱者」的方式。 對於每個已發佈的資料表,你可以指定每個操作(INSERT、UPDATE 或 DELETE)應以四種方式之一傳播至訂閱者:
指定異動複寫應先編寫指令碼,然後呼叫預存程序,以將變更傳播至「訂閱者」(預設值)。
指定變更應透過 INSERT、 UPDATE、 或 DELETE 陳述式來傳播(非 SQL Server 訂閱者的預設格式)。
指定使用自訂預存程序。
指定此動作不應在任何「訂閱者」處執行。 不會重複該類型的交易。
依預設,異動複寫會透過每個訂閱者上所安裝的一組預存程序,將變更傳播到訂閱者。 在「發行者」端的資料表中進行插入、更新或刪除操作時,作業會翻譯為對「訂閱者」端預存程序的呼叫。 儲存程序接受對應到資料表欄位的參數,允許用戶在訂閱者端變更這些欄位。
若要設定對交易式發行項之資料變更的傳播方法,請參閱< 設定對交易式發行項之資料變更的傳播方法>。
預設與自訂預存程序
複寫為每個資料表文章建立三個預設的儲存程序:
sp_MSins_<tablename>,負責處理插入。
負責處理更新的 sp_MSupd_<tablename>。
用於處理刪除的 sp_MSdel_<tablename>。
<程序中使用的表格名稱>取決於你如何將文章加入出版品,以及訂閱資料庫是否包含同名但擁有者不同的資料表。
你可以用在將文章新增至發行集時所指定的自訂程序,取代這些程序中的任何一個。 如果您的應用程式需要自訂邏輯,例如在訂閱者更新資料列時,將資料插入稽核表,請使用自訂程序。 欲了解更多關於指定自訂儲存程序的資訊,請參閱前一節列出的操作相關文章。
當你指定預設複製程序或自訂程序時,也會為每個程序指定呼叫語法。 如果你使用預設程序,複製會選擇預設呼叫語法。 呼叫語法決定提供給程序的參數結構,以及每個資料變更傳送到「訂閱者」的資訊量。 欲了解更多資訊,請參閱本文中的「呼叫儲存程序語法」章節。
使用自訂儲存程序的考量
使用自訂預存程序時,請記住下列考量:
你必須在儲存程序中支援邏輯;Microsoft 不支援自訂邏輯。
為避免與複製所用的交易衝突,請不要在自訂程序中使用明確的交易。
訂閱者的結構通常與 Publisher 的結構相同,但若使用欄位篩選,它也可以是 Publisher 架構的子集。 如果你需要隨著資料移動轉換結構,使訂閱者的結構不再是 Publisher 架構的子集,可以使用 SQL Server 2019 整合服務(SSIS)。 如需詳細資訊,請參閱 SQL Server Integration Services。
如果你對已發佈的資料表做結構變更,請重新產生自訂程序。 如需詳細資訊,請參閱重新產生自訂交易程序以反映結構描述變更。
如果你在 散發代理程式 的 -SubscriptionStreams 參數中使用大於 1 的值,請確保主鍵欄位的更新成功。 例如:
update ... set pk = 2 where pk = 1 -- update 1 update ... set pk = 3 where pk = 2 -- update 2如果 散發代理程式 使用多個連線,這兩次更新可能會在不同的連線上重複發生。 如果先套用更新 1,就沒問題。 如果先套用更新 2,則會回傳
0 rows affected,因為更新 1 尚未發生。 預設程序會處理此情況,若更新時沒有列受影響,則會產生錯誤:if @@rowcount = 0 if @@microsoftversion>0x07320000 exec sys.sp_MSreplraiserror 20598提出錯誤會迫使 散發代理程式 在單一連線上重試更新,且成功。 自訂預存程序必須包括類似的邏輯。
預存程序的呼叫語法
你可以使用五種不同的語法選項來呼叫交易複製所使用的程序:
CALL 語法。 使用此語法進行插入、更新與刪除。 依預設,複寫使用此語法進行插入和刪除。
SCALL 語法。 此語法僅用於更新。 依預設,複寫使用此語法進行更新。
MCALL 語法。 此語法僅用於更新。
XCALL 語法。 更新和刪除時請使用此語法。
VCALL。 可更新訂閱請使用此語法。 僅供內部使用。
每種方法傳送給訂閱者的資料量各不相同。 例如,SCALL 只傳遞更新實際影響的欄位值。 XCALL 需要所有欄位,不論更新是否影響它們,以及每欄所有舊資料值。 在許多情況下,SCALL 適合用於更新,但若您的應用程式在更新時需要所有資料值,XCALL 則支援此需求。
CALL 語法
INSERT 預存程序
處理 INSERT 語句的儲存程序會接收所有欄位插入的值:
c1, c2, c3,... cn
UPDATE 預存程序
處理 UPDATE 語句的儲存程序會接收文章中定義的所有欄位的更新值,接著是主鍵欄位的原始值。 此過程不嘗試判斷哪些欄位被更改:
c1, c2, c3,... cn, pkc1, pkc2, pkc3,... pkcn
DELETE 預存程序
處理 DELETE 敘述的儲存程序會接收主鍵欄位的值:
pkc1, pkc2, pkc3,... pkcn
SCALL 語法
UPDATE 預存程序
處理 UPDATE 敘述的儲存程序只會接收變更欄位的更新值,接著是主鍵欄位的原始值,然後是位元遮罩binary(n)()參數,指示變更欄位。 以下範例中,第 2 欄(c2)未改變:
c1, , c3,... cn, pkc1, pkc2, pkc3,... pkcn, bitmask
MCALL 語法
UPDATE 預存程序
處理 UPDATE 語句的儲存程序會接收文章中定義的所有欄位的更新值,接著是主鍵欄位的原始值,然後是一個位元遮罩(binary(n))參數,指示變更的欄位:
c1, c2, c3,... cn, pkc1, pkc2, pkc3,... pkcn, bitmask
XCALL 語法
UPDATE 預存程序
處理 UPDATE 敘述的儲存程序會接收文章中定義的所有欄位的原始值(前置影像),接著是文章中定義的所有欄位的更新值(後置影像):
old-c1, old-c2, old-c3,... old-cn, c1, c2, c3,... cn,
DELETE 預存程序
處理 DELETE 語句的儲存程序會接收文章中定義的所有欄位的原始值(之前的圖片):
old-c1, old-c2, old-c3,... old-cn
註釋
當您使用 XCALL 時,image 和 text 欄位的變更前映像值應為 NULL。
範例
下列程序是為 Adventure Works 範例資料庫中的 Vendor Table 建立的預設程序。
--INSERT procedure using CALL syntax
create procedure [sp_MSins_PurchasingVendor]
@c1 int,@c2 nvarchar(15),@c3 nvarchar(50),@c4 tinyint,@c5 bit,@c6 bit,@c7 nvarchar(1024),@c8 datetime
as
begin
insert into [Purchasing].[Vendor]([VendorID]
,[AccountNumber]
,[Name]
,[CreditRating]
,[PreferredVendorStatus]
,[ActiveFlag]
,[PurchasingWebServiceURL]
,[ModifiedDate])
values (
@c1
,@c2
,@c3
,@c4
,@c5
,@c6
,@c7
,@c8
)
end
go
--UPDATE procedure using SCALL syntax
create procedure [sp_MSupd_PurchasingVendor]
@c1 int = null,@c2 nvarchar(15) = null,@c3 nvarchar(50) = null,@c4 tinyint = null,@c5 bit = null,@c6 bit = null,@c7 nvarchar(1024) = null,@c8 datetime = null,@pkc1 int
,@bitmap binary(2)
as
begin
update [Purchasing].[Vendor] set
[AccountNumber] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [AccountNumber] end
,[Name] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [Name] end
,[CreditRating] = case substring(@bitmap,1,1) & 8 when 8 then @c4 else [CreditRating] end
,[PreferredVendorStatus] = case substring(@bitmap,1,1) & 16 when 16 then @c5 else [PreferredVendorStatus] end
,[ActiveFlag] = case substring(@bitmap,1,1) & 32 when 32 then @c6 else [ActiveFlag] end
,[PurchasingWebServiceURL] = case substring(@bitmap,1,1) & 64 when 64 then @c7 else [PurchasingWebServiceURL] end
,[ModifiedDate] = case substring(@bitmap,1,1) & 128 when 128 then @c8 else [ModifiedDate] end
where [VendorID] = @pkc1
if @@rowcount = 0
if @@microsoftversion>0x07320000
exec sp_MSreplraiserror 20598
end
go
--DELETE procedure using CALL syntax
create procedure [sp_MSdel_PurchasingVendor]
@pkc1 int
as
begin
delete [Purchasing].[Vendor]
where [VendorID] = @pkc1
if @@rowcount = 0
if @@microsoftversion>0x07320000
exec sp_MSreplraiserror 20598
end
go