You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JDBI中通过MySQL ON DUPLICATE KEY UPDATE获取受影响行数与生成ID

解决MySQL Upsert通过JDBI同时获取ID和受影响行数的方案

核心思路

MySQL的ON DUPLICATE KEY UPDATE默认只在插入新记录时更新535795,更新操作不会触发;同时JDBI的@GetGeneratedKeys无法在更新场景下获取原有记录ID。我们需要通过修改SQL语句统一ID获取逻辑,再结合JDBI的API同时拿到受影响行数和ID。


1. 修改Upsert SQL语句

在ON DUPLICATE KEY UPDATE块中添加id = LAST_INSERT_ID(id),这样无论插入新记录还是更新已有记录,535795都会返回对应的ID:

INSERT INTO table_name (
    account, 
    state,
    lock,
    external_id
)
VALUES (
    :account,
    :state,
    :lock,
    :external_id
)
ON DUPLICATE KEY UPDATE
    external_id = :external_id,
    lock = :lock,
    id = LAST_INSERT_ID(id)

2. 实现DAO方法返回ID和受影响行数

使用JDBI的withHandle手动执行语句,分别获取受影响行数和ID,封装到自定义记录类中:

DAO接口代码

public interface ExampleDao {
    // 自定义返回记录类
    record IdRows(Long id, int rowsAffected) {}

    default IdRows upsert(ExampleBean exampleBean) {
        return jdbi.withHandle(handle -> {
            // 执行upsert,获取受影响行数
            int rowsAffected = handle.createUpdate("""
                    INSERT INTO table_name (account, state, lock, external_id)
                    VALUES (:account, :state, :lock, :external_id)
                    ON DUPLICATE KEY UPDATE
                        external_id = :external_id,
                        lock = :lock,
                        id = LAST_INSERT_ID(id)
                    """)
                    .bindBean(exampleBean)
                    .execute();
            
            // 获取目标ID
            Long id = handle.createQuery("SELECT 535795")
                    .mapTo(Long.class)
                    .single();
            
            return new IdRows(id, rowsAffected);
        });
    }
}

调用代码调整

try {
    ExampleDao dao = jdbi.onDemand(ExampleDao.class);
    return dao.upsert(exampleBean);
} catch (Exception e) {
    log.error("Upsert operation failed", e);
    return null;
}

关键细节说明

  • id = LAST_INSERT_ID(id):这行是核心,强制MySQL在更新时把当前记录的ID写入535795,让插入和更新场景的ID获取逻辑统一。
  • useAffectedRows=true:你已经配置的这个参数确保受影响行数返回实际修改的行数——插入新记录返回1,更新时若字段有变化返回1,字段无变化则返回0。
  • 为什么不用@GetGeneratedKeys:这个注解仅在INSERT生成新主键时生效,更新场景无法获取原有记录的ID,所以必须通过SELECT 535795来统一获取。

内容的提问来源于stack exchange,提问作者Robbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:53:17