这更像是一个正确性问题。假设我的数据库中有一个包含主键列的表。在我的DAO代码中,我有一个名为insertRow(string key)的函数,如果表中不存在该键并且使用该键插入一个新行,则该函数将返回true。否则,如果该键已经存在,则返回false。让insertRow首先检查密钥是否存在更好/更糟或只是继续执行插入并捕获重复密钥错误?或者在单个选择语句中保存太微不足道的优化甚至令人担心?

所以在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;
  }
有帮助吗?

解决方案

尝试插入,然后捕获错误。

否则,您可能仍然在两个活动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.

您可以通过使用显式事务或设置事务隔离级别来缓解此问题,但它更容易使用第二种技术,除非您确定始终只对数据库运行一个应用程序线程。

其他提示

插入行,捕获重复键错误。我个人的选择

我认为这可能会表现得更好,具体取决于抛出异常的成本与两次击中db的成本。

只有通过测试两种情况才能确定

在我看来,这是使用异常的一个很好的例子(因为重复是例外的),除非你指望那里,大多数时候,已经是一行(即,你正在做的)插入,但如果存在则更新“逻辑。”

如果要更新代码的目的,那么您应该使用select或 INSERT ... ON DUPLICATE KEY UPDATE 子句(如果您的数据库引擎支持)。或者,make make一个为您处理此逻辑的存储过程。

第二个因为第一个选项击中了db两倍而第二个选项只击中一次。

简短的回答是你需要自己测试一下。我的直觉是,做一个小选择来检查存在会表现得更好,但是你需要在体积上验证这一点,看看哪个表现更好。

一般情况下,我不喜欢将我的错误检查完全留给异常引擎,无论我正在做什么。换句话说,如果我可以检查我正在做的事情是否有效而不仅仅是抛出异常,那通常就是我所做的。

但我建议使用 EXISTS 查询而不是 count(*)

if(exists (select 1 from mytable where key = "somekey"))
    return false
else
    insert the row

所有这一切(从抽象的,引擎中立的角度来看),我很确定MySQL有一些关键字,只有在主键不存在时才能用于将行插入表中。假设您可以使用特定于MySQL的关键字,这可能是您最好的选择。

另一个选择是将逻辑完全放在SQL语句中。

mysql中的另外两个选项是使用

insert ignore into....

insert into .... on duplicate key update field=value

在重复密钥更新字段=字段

上包含

请参阅: http://dev.mysql.com/doc /refman/5.0/en/insert.html

编辑: 您可以测试affected_rows是否有插件有效。

现在我已经在网上找到了Martin Fowler的书,一个不错的方法是使用关键表 - 请参阅第222页更多信息。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top