问题
如何避免客户端/服务器数据库中的主键冲突
背景
我正在同步多个数据库。我有一个中央SQL Server数据库和许多客户端SQL Server数据库。现在说我在数据库中有一个表X,它有一个主键ID。
在第一个客户端中,我们在表X中有以下ID:
X(客户1)
--------
1 | someValue中
2 | someValue中
3 | someValue中
4 | someValue中
在第二个客户端我有
X(客户2)
--------
1 | someValue中
2 | someValue中
3 | someValue中
4 | someValue中
当我同步时,我希望客户端只上传他们的数据而不是下载它们。
现在,当我将第一个客户端与服务器同步时,它将从(1 .. 4)添加主键。但是,当我与第二个客户端同步时,将有PRIMARY KEY CLASH。我该如何解决这个问题?
我正在使用SQL Server 2008 R2,Sync Framework和C#。
我已经考虑过将GUID用作主键的想法,这在我的情况下是不可行的,因为我正在处理遗留数据库。此外,重新设置IDENTITY值的想法有点容易出错。如何在不插入值的情况下增加标识列? P.S:主键设置为IDENTITY,增量为1。
答案 0 :(得分:5)
为了支持能够插入记录的分布式客户端,架构必须支持客户端DB创建没有冲突的行。这意味着要么为PK使用GUID,要么使用连锁密钥。 (ID + ClientID)*无论哪种方式,架构更改。
手动同步客户端数据库,否则意味着在插入或处理异常之前检查冲突的ID,然后替换ID或允许为冲突的记录生成身份。这意味着更新所有FK关系。耗时且容易出错。
答案 1 :(得分:2)
有几种方法可以实现。第一种是如果有一个保证的唯一键,上游和下游数据库都可以通过该唯一键来引用该记录。对于SQL Server,您需要的密钥类型是UNIQUEIDENTIFIER(又名GUID)。
现在,如果由于某种原因您无法使用UNIQUEIDENTIFIER,则第二个最佳选择是为位置或类似内容添加其他列。此列将标识记录来自的单个数据库。例如,第一个客户端的位置ID可能为1,第二个客户端可能为2,等等。然后,您可以将现有主键修改为此位置ID和当前ID的复合键。
第三种选择是根本不修改客户端数据库,而只是将位置id列添加到“master”数据库中的表。如果您在代码中手动同步,则代码需要考虑记录的来源,并根据需要添加ID。这可能很难,但肯定是可能的。
Baring您必须重新设置客户端数据库才能在特定点启动其身份值。例如,客户端1可能获得值1到10000,客户端2可能获得10001到20000.但是,您可以在此处看到失败的可能性。不仅如果客户端超出了您允许的范围,而且如果您设置了其他客户端并且有人搞砸了种子值。此外,修复所有现有客户将是一个完整的PITA。
作为旁注,当构建一个你知道将要有一个需要合并的分布式数据库的应用程序时,通常只需使用GUID作为主键即可。是的,它会对索引进行分段等,但在这种情况下,这些缺点优于完整的PITA以及最终将所有数据合并在一起时可能出现的错误。
答案 2 :(得分:0)
进一步向@Chris的第三个选项,如果您正在使用Sync Framework,您实际上可以“欺骗”它为服务器端PK添加额外的列。
请参阅:Part 1 – Upload Synchronization where the Client and Server Primary Keys are different