我经常想要为表添加一个值,或者如果它的键已经存在则更新该值。这可以通过多种方式实现,假设在示例中的'user_id'和'pref_key'列上设置了主键或唯一键:
1。盲插,如果收到重复键错误则更新:
// Try to insert as a new value
INSERT INTO my_prefs
(user_id, pref_key, pref_value)
VALUES (1234, 'show_help', 'true');
// If a duplicate-key error occurs run an update query
UPDATE my_prefs
SET pref_value = 'true'
WHERE user_id=1234 AND pref_key='show_help';
2。检查是否存在,然后选择或更新:
// Check for existence
SELECT COUNT(*)
FROM my_prefs
WHERE user_id=1234 AND pref_key='show_help';
// If count is zero, insert
INSERT INTO my_prefs
(user_id, pref_key, pref_value)
VALUES (1234, 'show_help', 'true');
// If count is one, update
UPDATE my_prefs
SET pref_value = 'true'
WHERE user_id=1234 AND pref_key='show_help';
第一种方式似乎更可取,因为它只需要一个查询用于新插入,两个用于更新,其中第二种方式总是需要两个查询。是否有任何我想念的东西虽然盲目地插入会是一个坏主意?
答案 0 :(得分:12)
查看http://dev.mysql.com/doc/refman/5.0/en/insert-select.html
中的ON DUPLICATE KEY语法INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
答案 1 :(得分:7)
有第三种MySQL方式,这是RDBMS
中首选的方式INSERT INTO my_prefs
(user_id, pref_key, pref_value)
VALUES (1234, 'show_help', 'true')
ON DUPLICATE KEY
UPDATE pref_value = 'true'
答案 2 :(得分:4)
就我个人而言,我从不喜欢基于异常的编程(期望在应用程序的正常操作中出现异常),对我而言,第二个示例更具可读性/可维护性。
在某些情况下,这会产生影响(例如非常严格的循环),但我认为应该有一个很好的理由来编写这样的代码而不是默认代码。
答案 3 :(得分:3)
如果你想通过插入双重调整来避免“异常”并且你想使用标准SQL(并且你的编程语言/数据库返回更新行的计数)那么使用下面的“SQL” - 命令(伪-code):
int i = SQL("UPDATE my_prefs ...");
if(i==0) {
SQL("INSERT INTO my_prefs ...");
}
这也考虑到 - 对于大多数用例 - 更新确实比插入更频繁。
答案 4 :(得分:2)
您可能可以使用REPLACE,或者如果使用更新的MySQL,您可以选择使用“INSERT ... ON DUPLICATE KEY UPDATE”
有几个人快速连续提起这个事实说“当你遇到问题时,总是检查MySQL文档”,因为它们很不错,在许多情况下直接导致解决方案。
答案 5 :(得分:2)
这些行会有并发INSERT吗?的DELETE
“ON DUPLICATE”听起来很棒(行为正是你想要的)只要你不关心非MySQL数据库的可移植性。
“盲插”似乎合理且健壮,前提是永远不会删除行。 (如果由于行存在而INSERT大小写失败,则后续的UPDATE应该成功,因为该行仍然存在。但是如果删除行则假设为假 - 那么您需要重试逻辑。)在没有“ON DUPLICATE”的其他数据库上,如果发现延迟不好,可以考虑进行优化:通过将此逻辑放在存储过程中,可以避免已存在的数据库往返。
如果存在并发INSERT,那么“检查存在”是非常棘手的。可以在SELECT和UPDATE之间添加行。事务甚至不会真正有用 - 我认为即使在隔离级别“可序列化”,您也会看到“由于并发更新而无法序列化访问”错误(或者无论MySQL等效错误消息是什么)。你需要重试逻辑,所以我要说上面那个建议使用这种方法来避免“基于异常的编程”的人是错误的,因为建议首先出于同样的原因进行UPDATE的人。
答案 6 :(得分:0)
据我所知,第一种方式是首选方式。
答案 7 :(得分:0)
在您的DAO模型中,您可以拥有一个id字段。
如果设置为null / -1 / whatever,则数据尚未保留。
当您持久化(或从数据库中检索)时,请将其设置为数据库中的id值。
您的persist方法可以检查ID并将其传递给update()或add()实现。
缺陷:与数据库等不同步我确信还有更多,但我真的应该完成一些工作......
答案 8 :(得分:0)
只要您使用MySQL
,就可以使用ON DUPLICATE
关键字。例如:
INSERT INTO my_prefs (user_id, pref_key, pref_value) VALUES (1234, 'show_help', 'true')
ON DUPLICATE KEY UPDATE (pref_key, pref_value) VALUES ('show_help', 'true');