适用范围:SQL Server
注意
此功能从 2012 到 2016 的 SQL Server 版本中仍然受支持。 在 SQL Server的未来版本中将删除此功能。 请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。
事务复制支持在订阅服务器中通过可更新订阅和对等复制来进行更新。 下面介绍两种可更新订阅:
立即更新。 发布服务器和订阅服务器必须处于连接状态,才能在订阅服务器上更新数据。
队列更新。发布服务器和订阅服务器不必保持连接,即可更新订阅服务器上的数据。 可以在订阅服务器或发布服务器脱机时进行更新。
在订阅服务器中更新数据时,首先将数据传播到发布服务器,然后再传播到其他订阅服务器。 如果采用立即更新,则这些更改会通过两阶段提交协议立即传播。 如果使用排队更新,更改将存储在队列中;当网络连接可用时,系统会在发布服务器端异步应用这些排队事务。 由于更新异步传播至发布服务器,所以发布服务器或另一台订阅服务器有可能更新同一数据,而在应用更新时会发生冲突。 将根据创建发布时设置的冲突解决策略检测和解决冲突。
如果在新建发布向导中创建具有可更新订阅的事务发布,将同时启用立即更新和排队更新。 如果使用存储过程创建发布,则可以启用一个或两个选项。 创建发布的订阅时,可以指定要使用的更新模式。 如有必要,以后可以在两种更新模式之间切换。 有关详细信息,请参阅下面的“在更新模式之间切换”部分。
若要启用事务发布的可更新订阅,请参阅 Enable Updating Subscriptions for Transactional Publications。
若要创建事务发布的可更新订阅,请参阅创建事务发布的可更新订阅 (Management Studio)。
在更新模式之间切换
使用可更新订阅时,可以指定订阅使用一种更新模式,然后在应用程序需要时再切换到另一种更新模式。 例如,可以指定订阅使用立即更新,但如果因系统故障而导致网络连接断开,则切换到排队更新。
注意
复制不会自动切换更新模式。 必须通过 SQL Server Management Studio 设置更新模式,否则你的应用程序必须调用 sp_setreplfailovermode (Transact-SQL) 来切换更新模式。
如果从立即更新切换为排队更新,则在订阅服务器与发布服务器重新连接,并且队列读取器代理已将队列中所有待处理消息应用到发布服务器之前,将无法切换回立即更新。
切换更新模式
若要切换更新模式,必须为这两种更新模式都启用发布和订阅,然后再根据需要进行切换。 有关详细信息,请参阅
切换可更新事务性订阅的更新模式
使用可更新订阅的注意事项
将某个发布启用为更新订阅或排队更新订阅后,便无法再对该发布禁用此选项(尽管订阅不一定需要使用此选项)。 若要禁用该选项,必须删除发布并创建一个新发布。
不支持重新发布数据。
出于跟踪的目的,复制将在已发布的表中添加 msrepl_tran_version 列。 由于此附加列,所有 INSERT 语句都应包括列列表。
若要对支持可更新订阅的发布中的表进行架构更改,必须先在发布服务器和各订阅服务器上停止该表的所有活动,并且必须先将待处理的数据更改传播到所有节点,然后才能进行任何架构更改。 这可以确保未完成的事务不会与挂起的架构更改发生冲突。 架构更改传播到所有节点后,可以在已发布的表上恢复活动。 有关详细信息,请参阅停止复制拓扑(复制 Transact-SQL 编程)。
如果计划切换更新模式,则在初始化订阅后,队列读取器代理必须至少运行一次(默认情况下,队列读取器代理连续运行)。
如果订阅服务器数据库进行了水平分区,且分区中有在订阅服务器上存在而在发布服务器中不存在的行,那么订阅服务器将无法更新这些预先存在的行。 尝试更新这些行时会返回错误。 应先从表中删除这些行,然后再在发布服务器中添加这些行。
使用唯一筛选索引时,具有排队更新订阅服务器的事务复制可能会出现性能缓慢问题。 如果在具有唯一筛选索引的项目上发生冲突,则冲突解决会导致订阅服务器对唯一筛选索引未涵盖的那些行执行额外的删除和插入操作。
订阅者端的更新
即使订阅过期或处于不活动状态,订阅服务器中的更新仍会传播到发布服务器中。 请确保删除或重新初始化此类订阅。
如果使用 TIMESTAMP 或 IDENTITY 列,并且这些列按其基础数据类型复制,则不应在订阅服务器上更新这些列中的值。
订阅服务器不能更新或插入 text、 ntext 或 image 值,因为不能在复制更改跟踪触发器中从插入或删除的表中读取数据。 同样,订阅服务器不能使用 WRITETEXT 或 UPDATETEXT 更新或插入 text 或 image 值,因为这些数据会被发布服务器覆盖。 相反,你可以将 text 和 image 列拆分到单独的表中,并在一个事务中对这两个表进行修改。
若要更新订阅服务器上的大型对象,请分别使用数据类型 varchar(max)、 nvarchar(max)、 varbinary(max) ,而不要使用 text、 ntext和 image 数据类型。
不允许对唯一键(包括主键)进行生成重复项的更新(例如,格式为
UPDATE <column> SET <column> =<column>+1的更新),这些更新将因为违反唯一性而被拒绝。 这是因为,在订阅服务器上执行的集合更新会通过复制作为针对每个受影响行的单独 UPDATE 语句进行传播。如果订阅服务器数据库进行了水平分区,且分区中有在订阅服务器上存在而在发布服务器中不存在的行,那么订阅服务器将无法更新这些预先存在的行。 尝试更新这些行时会返回错误。 应当先从表中删除这些行,然后再插入这些行。
用户定义的触发器
如果应用程序需要在订阅服务器中使用触发器,则应在发布服务器和订阅服务器中使用
NOT FOR REPLICATION选项来定义触发器。 这可以确保触发器仅在原始数据发生更改时触发,而不会在该更改被复制时触发。确保当复制触发器更新表时,不会触发用户定义的触发器。 这可以通过在用户定义的触发器的正文中调用 sp_check_for_sync_trigger 过程来实现。 有关详细信息,请参阅 sp_check_for_sync_trigger (Transact-SQL)。
立即更新
对于立即更新订阅,订阅服务器上的更改会传播到发布服务器,并使用 Microsoft 分布式事务处理协调器 (MS DTC) 进行应用。 请确保发布服务器和订阅服务器中安装并配置了 MS DTC。 有关详细信息,请参阅 Windows 文档。
立即更新订阅使用的触发器需要连接到发布服务器才能复制更改。
如果发布允许立即更新订阅,且该发布中的文章具有列筛选,则无法筛选掉没有默认值的非空列。
排队等待更新
合并发布中包含的表也不能作为允许排队更新订阅的事务发布的一部分进行发布。
使用排队更新时,建议不要对主键列进行更新,因为主键被用作所有查询的记录定位器。 当冲突解决策略设置为“订阅服务器优先”时,更新主键应谨慎进行。 如果同时在发布服务器和订阅服务器中更新主键,将获得具有不同主键的两行。
对于数据类型为 SQL_VARIANT 的列:当在订阅服务器处插入或更新数据时,队列读取器代理在将数据从订阅服务器复制到队列时,会按下列方式对其进行映射:
将BIGINT, DECIMAL, NUMERIC, MONEY和 SMALLMONEY 映射到 NUMERIC。
将BINARY 和 VARBINARY 映射到 VARBINARY 数据。
冲突检测和解决
对于“订阅服务器优先”冲突策略:对于主键列的更新,不支持冲突解决。
复制并不会解决由于外键约束失败而引起的冲突。
如果预计不会发生冲突,并且数据分区良好(订阅服务器不会更新相同的行),则可以在发布服务器和订阅服务器上使用外键约束。
如果预期会发生冲突:如果使用“订阅服务器获胜”冲突解决方式,则不应在发布服务器或订阅服务器上使用外键约束;如果使用“发布服务器获胜”冲突解决方式,则不应在订阅服务器上使用外键约束。