事务复制后的PK违规

时间:2012-05-24 07:36:41

标签: sql-server sql-server-2008 database-replication

我将应用程序设置为将事务复制推送到将用于紧急故障转移的备用计算机。复制似乎正常,任何对服务器1的插入都将自动显示在服务器2上。

但是,我无法完成故障转移工作。在服务器1变得不可用的情况下(这是唯一使用服务器2的情况,因此复制是单向的),我们的想法是工作应该在服务器2处继续,并且过渡应该在某种程度上是无缝的因为所有数据都已被复制。

但是当转移到服务器2时,确保已经传输了服务器1上的所有更新后,我会继续获得某些表的主键冲突异常。

  

违反PRIMARY KEY约束'PK_TableA'。无法在对象'dbo.TableA'中插入重复键。

一个简单的查询,例如

INSERT INTO TableA (Field1, Field2, TableB_ID) VALUES ('a','b', 6)

会产生上述错误。似乎当我指示表分配自己的标识时,通过从查询中省略它(TableAID int identity(1,1)字段),SQL Server将自动分配违反PK的ID约束。为什么会这样?


TableAINSERTDELETE的触发器执行简单的非规范化作业

UPDATE TableB
SET Count = (SELECT COUNT(1) FROM TableA WHERE TableB.ID = TableA.TableB_ID)
WHERE ID IN(
    -- Fetch affected ID's from deleted or inserted rows
    SELECT DISTINCT TableB_ID FROM deleted
    UNION
    SELECT DISTINCT TableB_ID FROM inserted
)

这在复制时不小心不是Server 2数据库的一部分,之后我插入了它。 TableB.Count字段的一致性对于手头的任务并不重要。 PK违规发生在服务器2中存在触发器之前以及创建之后。


在发布者和订阅者处,产生违规的ID字段具有以下定义:

[ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL

我认为NOT FOR REPLICATION部分在发布服务器上是多余的,因为没有复制作业会写入它,但我也看不出它应该是问题的原因。

2 个答案:

答案 0 :(得分:1)

必须在复制方案中显式管理

IDENTITY范围。

在您的情况下,您需要为每个IDENTITY找到一个大于所有当前值的值。

然后,您可以将一台服务器配置为仅分配奇数,而另一台服务器仅分配偶数。 JUst将定义更改为发布者上的IDENTITY(MAXPLUS1,2)和订阅者上的IDENTITY(MAXPLUS2,2)。

显然,您可以扩展此计划以支持任意数量的嫌疑人。

答案 1 :(得分:0)

我遇到了同样的问题-CheckIdent方法也是拯救我的方法,这是一个快速而肮脏的脚本,它使我得以前进。

如果将此查询的输出发送到文本(不是网格结果,这是SSMS工具栏上的按钮),则可以将其复制/粘贴到新的查询窗口中,并获得另一组输出,该输出具有所有的checkIdent命令数据库中具有正确种子值的每个表(假设您始终在具有标识的每个表上加一)。然后,您可以获取这些结果(如果在第二个查询窗口中看到一些空值,则可能需要手动将其省略),然后将其复制/粘贴到第三个查询窗口中并执行。

这不是一个出色的解决方案,但是如果您处于绑定状态(您的主数据库服务器已离开并且需要一个副本(也许是唯一的副本?)),则可以使数据库备份并真正快速地运行。服务器。

SELECT 'select ''[' + s.name + '].[' + t.name + ']'' as TableName, ''DBCC CHECKIDENT(''''[' + s.name + '].[' + t.name + ']'''', ''''RESEED'''','' + cast(max ([' + s.name + '].[' + t.name + '].[' + i.name + '])' + '+1 AS varchar(50)) + '')'' as reseed from [' + s.name + '].[' + t.name + ']'
+ char(13) + char (10) + 'union all' 
FROM sys.schemas AS s
INNER JOIN sys.tables AS t
ON s.[schema_id] = t.[schema_id]
INNER JOIN sys.identity_columns i
on i.[object_id] = t.[object_id]
order by t.name