测试数据库中重复键的最佳方法

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 页。

【讨论】:

以上是关于测试数据库中重复键的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

数据驱动测试-从方法探研到最佳实践

Django:关于自动递增主键的最佳实践

巨杉数据库SequoiaDB巨杉Tech | 分布式数据库Sysbench测试最佳实践

为 Junit 测试克隆现有数据库的最佳方法?

测试一组枚举的相互成员资格的最佳方法

测试 SQL 查询的最佳方法 [关闭]