由於排隊更新訂閱允許在多個位置修改相同數據,因此在發行者同步數據時,可能會發生衝突。 當變更與發行者同步處理時,複寫會偵測任何衝突,並使用您在建立發行集時選取的解決原則來解決這些衝突。 可能發生下列衝突:
更新並插入衝突。 當相同數據在兩個位置變更時,就會發生此衝突。 一個改變贏了,另一個改變輸了。
刪除衝突。 當在同一個位置刪除相同的數據列,並在另一個位置變更時,就會發生此衝突。
衝突偵測和解決可能是耗時且耗用大量資源的程式;因此,最好藉由建立數據分割來將應用程式中的衝突降到最低,讓不同的訂閱者修改不同的數據子集。
偵測衝突
建立發行集並啟用佇列更新時,複寫會將 uniqueidentifier 欄位(msrepl_tran_version)預設值為 newid() 新增至基礎資料表。 當發行的數據在「發行者」或「訂閱者」端變更時,數據列會收到新的全域唯一標識碼(GUID),以指出新的數據列版本存在。 佇列讀取器代理程式會在同步處理期間使用此數據行來判斷衝突是否存在。
佇列中的交易會維護舊版和新版的行版本值。 在發行者端套用交易時,會比較交易中的 GUID 和發行集中的 GUID。 如果儲存在交易中的舊 GUID 符合發行集中的 GUID,則會更新發行集,並將數據列指派給訂閱者所產生的新 GUID。 藉由用交易中的 GUID 更新出版物,您在出版物和交易中都有相符的行版本。
如果儲存在交易中的舊 GUID 不符合發行集中的 GUID,則會偵測到衝突。 發行集中的新 GUID 表示存在兩個不同的數據列版本:訂閱者所提交的交易中有一個,另一個存在於發行者端。 在此情況下,在同步處理此訂閱者交易之前,發行集內的另一個訂閱者或發行者更新了相同數據列。
不同於合併式複寫,GUID 數據行的使用不會用來識別數據列本身,而是用來檢查數據列是否已變更。
解決衝突
當您使用佇列更新建立發行集時,您可以選取在偵測到任何衝突時要使用的衝突解決器。 衝突解決器會控管佇列讀取器代理程式如何處理同步處理期間所遇到的相同數據列的不同版本。 只要沒有發行集的訂閱,您就可以在建立發行集之後變更衝突解決原則。 衝突解決器選項如下:
發行者獲勝 (預設值)
發行者獲勝並重新初始化訂閱
訂閱者獲勝
衝突會記錄下來,而且可以使用衝突查看器來檢視。
將佇列更新衝突的解決政策設定為
SQL Server Management Studio: 設定佇列更新衝突解決選項 (SQL Server Management Studio)
復寫 Transact-SQL 程式設計: 啟用可更新訂閱功能以支援交易式發行
檢視數據衝突
- SQL Server Management Studio: 檢視交易式發行集的數據衝突 (SQL Server Management Studio)
發行者贏
當衝突解決設定為發行者獲勝時,交易一致性會根據發行者端的數據進行維護。 衝突的交易會在起始交易的訂閱者端復原。
佇列讀取器代理程式偵測到衝突時,會產生補償命令,並透過在散發資料庫中張貼這些命令來傳播給訂閱者。 散發代理程式接著會將補償命令套用至產生衝突交易的訂閱者。 補償動作會更新訂閱者上的資料列,使其與發行者上的資料列一致。
在套用補償命令之前,可以讀取最終會在訂閱者端回復的交易結果。 這相當於骯髒的讀取(讀取未認可的隔離等級)。 後續可能發生的相依交易是沒有補償的。 不過,會接受交易界限,且交易內的所有動作都會認可,或在發生衝突時回復。
發行者獲勝,訂閱被重新初始化
重新初始化訂閱者以解決衝突會在訂閱者端維持嚴格的交易一致性,但如果發行集包含大量數據,可能會很耗時。
當佇列讀取器代理程式偵測到衝突時,佇列中的所有剩餘交易(包括衝突中的交易)都會遭到拒絕,且訂閱者會標示為重新初始化。 發行集產生的下一個快照集是由散發代理程式套用至訂閱者。
訂閱者獲勝
訂閱者獲勝原則下的衝突偵測是指,最後一次訂閱者交易更新發行者時獲勝。 在此情況下,偵測到衝突時,仍會使用訂閱者傳送的交易,並更新發行者。 此原則適用於這類變更不會危害資料完整性的應用程式。