这更像是一个正确性问题。假设我的数据库中有一个包含主键列的表。在我的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;
}
答案 0 :(得分:6)
插入行,捕获重复键错误。我个人的选择
我认为这可能会表现得更好,这取决于抛出异常的成本与两次击中db的成本。
只有通过测试两种情况才能确定
答案 1 :(得分:3)
在我看来,这是使用异常的一个很好的例子(因为副本是例外的),除非你指望那里,大多数时候,已经是一行(即,你正在做“插入” ,但如果存在“逻辑,则更新。”
如果要更新代码的目的,那么您应该使用select或INSERT ... ON DUPLICATE KEY UPDATE
子句(如果数据库引擎支持)。或者,创建一个为您处理此逻辑的存储过程。
答案 2 :(得分:3)
尝试插入,然后捕获错误。
否则,您可能仍然在两个活动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 :(得分:2)
第二个因为第一个选项击中了db两倍而第二个选项只击中一次。
答案 4 :(得分:0)
简短的回答是你需要自己测试一下。我的直觉是,做一个小选择来检查存在会表现得更好,但是你需要在体积上验证自己,看看哪个表现更好。
一般情况下,我不喜欢将我的错误检查完全留给异常引擎,无论我正在做什么。换句话说,如果我可以检查我正在做的事情是否有效而不仅仅是抛出异常,那通常就是我所做的。
但我建议使用EXISTS
查询而不是count(*)
if(exists (select 1 from mytable where key = "somekey"))
return false
else
insert the row
所有这一切(从抽象的,引擎中立的角度来看),我很确定MySQL有一些关键字,只有在主键不存在时才能用于将行插入表中。假设您可以使用特定于MySQL的关键字,这可能是您最好的选择。
另一个选择是将逻辑完全放在SQL语句中。
答案 5 :(得分:0)
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是否有插件有效。
答案 6 :(得分:0)
现在我已经在网上找到了Martin Fowler的书,一个体面的方法是使用key table - 请参阅第222页了解更多信息。