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

批量插入MariaDB成功但ReturnGeneratedKeys返回空值的问题求助

解决MariaDB批处理插入后无法获取生成键的问题

看起来你遇到的问题是批处理插入成功,但无法通过getGeneratedKeys()获取自增主键,这在使用MariaDB JDBC驱动配合executeBatch()时确实容易出现,尤其是和autoCommit的设置有关。我来帮你分析原因并给出修复方案:

核心问题分析

当autoCommit设为true时,执行executeBatch()后连接会自动提交事务,这时候JDBC驱动可能已经释放了与生成键相关的资源,导致后续调用getGeneratedKeys()返回空的结果集。虽然你说设为false时数据插不进去,但那是因为你没有手动提交事务——只要调整流程,关闭autoCommit并手动提交,就能同时解决数据插入和生成键获取的问题。

另外,我注意到你的代码里有个小笔误:ps2.setShort(7, equip.getProperty("INT"));这里重复设置了INT,应该是LUK,这个也需要修正,避免数据错误。

修复后的代码

try (Connection con = DatabaseConnection.getConnection()) {
    // 关闭自动提交,手动控制事务
    con.setAutoCommit(false);
    
    try (PreparedStatement ps = con.prepareStatement(
            "INSERT INTO items (chrid, accountid, type, pos, itemid) VALUES (?,?,?,?,?)",
            Statement.RETURN_GENERATED_KEYS)) {
        
        ArrayList<Pair<Integer, Equip>> equips = new ArrayList<>();
        for (Pair<Integer, Integer> item : items) {
            equips.add(itemCreationSystem.createEquip(item.right));
            ps.setInt(1, dbId.dbId);
            ps.setInt(2, client.accountId);
            ps.setInt(3, 0);
            ps.setInt(4, item.left);
            ps.setInt(5, item.right);
            ps.addBatch();
        }
        
        // 执行第一个批处理
        ps.executeBatch();
        
        // 获取生成的主键
        try (ResultSet rs = ps.getGeneratedKeys()) {
            try (PreparedStatement ps2 = con.prepareStatement(
                    "INSERT INTO equips (itemKey, slots, successfulUpgrades, str, dex, intel, luk, hp, mp, " +
                    "wAtk, mAtk, wDef, mDef, equipPos)")) {
                
                while (rs.next()) {
                    Pair<Integer, Equip> pair = equips.remove(0);
                    Equip equip = pair.right;
                    ps2.setInt(1, rs.getInt(1));
                    ps2.setShort(2, equip.upgradeSlots);
                    ps2.setShort(3, equip.successfulUpgrades);
                    ps2.setShort(4, equip.getProperty("STR"));
                    ps2.setShort(5, equip.getProperty("DEX"));
                    ps2.setShort(6, equip.getProperty("INT"));
                    // 修正:把重复的INT改成LUK
                    ps2.setShort(7, equip.getProperty("LUK"));
                    ps2.setShort(8, equip.getProperty("HP"));
                    // 注意:原代码写的是MMP,需确认数据库字段是mp还是mmp,避免字段不匹配
                    ps2.setShort(9, equip.getProperty("MP"));
                    ps2.setShort(10, equip.getProperty("PAD"));
                    ps2.setShort(11, equip.getProperty("MAD"));
                    ps2.setShort(12, equip.getProperty("PDD"));
                    ps2.setShort(13, equip.getProperty("MDD"));
                    ps2.setInt(14, pair.left);
                    ps2.addBatch();
                }
                
                // 执行第二个批处理
                ps2.executeBatch();
            }
        }
        
        // 所有操作完成后,手动提交事务
        con.commit();
    } catch (SQLException e) {
        // 出错时回滚事务,保证数据一致性
        con.rollback();
        e.printStackTrace();
    }
} catch (SQLException e) {
    e.printStackTrace();
}

关键调整点

  1. 关闭autoCommit:将连接的自动提交设为false,让所有操作处于同一个事务中,避免提前释放生成键相关的资源。
  2. 手动提交事务:在所有批处理执行完成且无错误后,调用con.commit()提交数据,确保数据成功插入。
  3. 事务回滚:如果任何步骤抛出异常,调用con.rollback()回滚所有操作,防止出现部分插入的不一致情况。
  4. 修正字段赋值错误:修复了重复设置INT的问题,同时核对了MP字段的赋值(原代码写的MMP需和数据库字段名对应)。

额外建议

  • 确保你使用的是最新版本的MariaDB JDBC驱动(Connector/J 3.0.0+),旧版本对批处理生成键的支持可能不完善。
  • 确认items表的主键是自增字段(比如itemKey INT AUTO_INCREMENT PRIMARY KEY),这是RETURN_GENERATED_KEYS生效的前提。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:32:22