MySQL使用主键和唯一键更新重复键

wz1wpwve  于 2022-12-10  发布在  Mysql
关注(0)|答案(2)|浏览(267)

我有一个表,其中包含一个自动递增的主键和一个唯一键:

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`)

如果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方法。当前密钥条目包含多个密钥:[{GENERED_KEY=594},{GENERATED_KEY=595}]
有人知道这是什么原因吗?

cmssoen2

cmssoen21#

这是我自己刚遇到的。根据此处的文档:
https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
使用ON DIPLICATE KEY UPDATE时,如果该行作为新行插入,则每行受影响的行值为1,如果更新现有行,则为2
因此,当执行查询时,如果插入新记录,则返回其ID。如果该记录已经存在,则更新现有记录。如果因为值都匹配而不需要更新,则返回一个ID,修改的行数为0。但是,如果更新记录,则返回ID,修改的行数为2。密钥持有者假设已经修改了两行(即使只修改了一行),并且错误地返回了ID加上下一个顺序ID(即ID加1)。
为了解决这个问题,在尝试调用getkey之前,我只检查了getKey中的计数。如果getKeys中有多个值,我就不会调用GetKey。

6kkfgxo0

6kkfgxo02#

假设在重复的情况下,临时插入的行将具有更大的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一起工作。

相关问题