我有一个带有自动增量主键的表,也有一个唯一的键:
CREATE TABLE `product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`canonical_url` varchar(750) CHARACTER SET latin1 NOT NULL,
...
PRIMARY KEY (`id`),
UNIQUE KEY `canonical_url_idx` (`canonical_url`)
im使用ON重复关键功能来更新记录,如果Canonical_url已经存在:
"INSERT INTO product(id, canonical_url, name VALUES(?, ? ?) ON DUPLICATE KEY UPDATE name=VALUES(name), id=LAST_INSERT_ID(id)"
KeyHolder productKeyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(productSql, new String[] {"id"});
ps.setInt(1, id);
ps.setString(2, canonicalUrl);
ps.setString(3, name);
}, productKeyHolder);
final int productId = productKeyHolder.getKey().intValue();
问题是我遇到了这个错误:
仅当返回单键时,才应使用getKey方法。当前密钥条目包含多个键:[{generated_key = 594},{generated_key = 595}]
有人知道是什么原因引起的?
我自己遇到了这个。根据此处的文档:
https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
使用重复的密钥更新,如果将行插入新行,则每行影响行值为1,并且如果更新了现有行,则 2 。
因此,当查询执行时,如果插入了新记录,则返回ID。如果记录已经存在,则现有记录已更新。如果不需要更新,因为所有值全部匹配,则返回一个ID,并且修改的行数为0。但是,如果记录已更新,则返回ID,并且修改的行数为 2 。关键持有人假设已经修改了两个行(即使仅一行),并且错误地返回ID加上下一个顺序ID(即ID加1)。
为了解决这个问题,我只是在尝试致电GetKey之前检查了GetKeys中的计数。如果GetKeys中有多个值,我不会称呼GetKey。
假设在重复的情况下,临时插入的行将具有更大的ID,以下是:
public static int getGeneratedKeyOnDuplicate(KeyHolder keyHolder)
{
int id = 0;
List<Map<String, Object>> keyList = keyHolder.getKeyList();
if (keyList.size() == 1 && keyHolder.getKey() != null)
id = keyHolder.getKey().intValue();
else if (keyList.size() > 1)
{
id = keyList.stream()
.map((Map<String, Object> key) -> ((Number) key.get("GENERATED_KEY")).intValue())
.min(Comparator.comparing(Integer::valueOf))
.get();
}
return id;
}
,但请意识到keyHolder.getKey()
是java.math.BigInteger
的实例,因此我不确定这将如何使用具有很大价值的id
。