由于排队更新订阅允许修改多个位置的相同数据,因此在发布服务器上同步数据时可能存在冲突。 当更改与发布服务器同步时,复制会检测任何冲突,并使用创建发布时选择的解决策略解决这些冲突。 可能发生以下冲突:
更新并插入冲突。 当同一数据在两个位置发生更改时,会发生此冲突。 变革赢了,另一个输了。
删除冲突。 当在同一个位置删除同一行并在另一个位置更改时,会发生此冲突。
冲突检测和解决可能是一个耗时和资源密集型过程;因此,最好通过创建数据分区来最大程度地减少应用程序中的冲突,以便不同的订阅服务器修改不同的数据子集。
检测冲突
创建发布并启用排队更新时,复制会在基础表中添加一个 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)
发布者胜出
当冲突解决设置为发布服务器获胜时,会根据发布服务器上的数据维护事务一致性。 冲突事务在发起它的订阅服务器上回滚。
队列读取器代理检测到冲突,并生成补偿命令,通过发布到分发数据库将这些命令传播到订阅者。 然后,分发代理将补偿命令应用于发起冲突事务的订阅者。 补偿操作更新了订阅方的行,以匹配发布方的行。
在应用补偿命令之前,可以读取最终将在订阅者处回滚的事务结果。 这相当于脏读(读取未提交的隔离级别)。 对可能发生的后续相关交易没有任何补偿。 但是,会遵循事务边界,并且事务中的所有操作要么提交,要么在发生冲突时回滚。
发布商胜出并重新初始化订阅
重新初始化订阅服务器以解决冲突在订阅服务器上保持严格的事务一致性,但如果发布包含大量数据,则可能很耗时。
当队列读取器代理检测到冲突时,队列中的所有剩余事务(包括冲突中的事务)将被拒绝,订阅服务器将被标记为重新初始化。 为发布生成的下一个快照由分发代理应用到订阅者。
订阅者获胜
在“订阅者优胜策略”下,冲突检测意味着更新发布者的最后一个订阅者事务获胜。 在这种情况下,检测到冲突时,仍会使用订阅服务器发送的事务并更新发布服务器。 此策略适用于此类更改不会损害数据完整性的应用程序。