测试数据库中重复键的最佳方法
Posted
技术标签:
【中文标题】测试数据库中重复键的最佳方法【英文标题】:Best way to test for duplicate keys in a database 【发布时间】:2010-11-03 09:15:40 【问题描述】:这更像是一个正确性问题。假设我的数据库中有一个带有主键列的表。在我的 DAO 代码中,我有一个名为 insertRow(string key) 的函数,如果表中不存在该键,该函数将返回 true 并使用该键插入一个新行。否则,如果已经存在具有该键的行,则返回 false。让 insertRow 首先检查密钥的存在是更好还是更糟,还是继续进行插入并捕获重复的密钥错误?还是节省单个 select 语句太微不足道而无需担心?
所以在 sudo 代码中:
boolean insertRow(String key)
//potentially a select + insert
if(select count(*) from mytable where key = "somekey" == 0)
insert into mytable values("somekey")
return true;
return false;
或
boolean insertRow(String key)
try
//always just 1 insert
insert into mytable values("somekey")
return true;
catch (DuplicateKeyException ex)
return false;
【问题讨论】:
如果您有 Martin Fowler 的《企业应用程序架构模式》一书,我敢肯定他在他的“身份字段”模式中提供了一些很好的指导。当然,在没有某种锁定的情况下检查最后一个键是很危险的。 看起来您可以在 Google 图书上查看它-books.google.co.uk/… 【参考方案1】:插入行,捕获重复键错误。我个人的选择
我认为这可能会表现得更好,这取决于抛出异常的成本与两次访问数据库的成本。
只有通过测试这两种情况才能确定
【讨论】:
【参考方案2】:尝试插入,然后捕获错误。
否则,您可能仍然在两个活动 SPID 之间存在并发问题(假设系统上同时有两个 Web 用户),在这种情况下,您必须捕获错误无论如何:
User1: Check for key "newkey"? Not in database.
User2: Check for key "newkey"? Not in database.
User1: Insert key "newkey". Success.
User2: Insert key "newkey". Duplicate Key Error.
您可以通过使用显式事务或设置事务隔离级别来缓解这种情况,但使用第二种技术更容易,除非您确定只有一个应用程序线程始终针对数据库运行。
【讨论】:
【参考方案3】:在我看来,这是使用异常的绝佳案例(因为重复项是异常的),除非您在大多数情况下指望那里已经成为一行(即,您正在执行“插入,但如果存在则更新”逻辑。)
如果代码的目的是更新,那么您应该使用 select 或 INSERT ... ON DUPLICATE KEY UPDATE
子句(如果您的数据库引擎支持)。或者,创建一个为您处理此逻辑的存储过程。
【讨论】:
好点,大部分时间不会发生key冲突。【参考方案4】:第二个,因为第一个选项会命中两倍的数据库,而第二个只会命中一次。
【讨论】:
【参考方案5】:简短的回答是您需要自己测试它。我的直觉是,做一个小的选择来检查是否存在会表现得更好,但你需要自己验证一下,看看哪个表现更好。
一般来说,我不喜欢将我的错误检查完全留给我正在做的任何事情的异常引擎。换句话说,如果我可以检查我正在做的事情是否有效,而不仅仅是抛出异常,那通常就是我所做的。
不过,我建议使用EXISTS
查询而不是count(*)
if(exists (select 1 from mytable where key = "somekey"))
return false
else
insert the row
话虽这么说(从抽象的、引擎中立的角度来看),我很确定 mysql 有一些关键字可用于仅在主键不存在时将行插入表中。假设您可以使用 MySQL 特定的关键字,这可能是您最好的选择。
另一种选择是将逻辑完全放在 SQL 语句中。
【讨论】:
【参考方案6】:mysql中的另外两个选项是使用
insert ignore into....
和
insert into .... on duplicate key update field=value
包括on duplicate key update field=field
见:http://dev.mysql.com/doc/refman/5.0/en/insert.html
编辑: 您可以测试affected_rows 是否插入有效果。
【讨论】:
Oracle 和 SQL Server 2008 上也存在类似的语句:MERGE。【参考方案7】:现在我在网上找到了 Martin Fowler 的书,一个不错的方法是使用key table- 更多信息请参见第 222 页。
【讨论】:
以上是关于测试数据库中重复键的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章