Java操作MySQL插入数据触发子行更新外键错误,如何获取自增ID_USER插入关联表
问题原因&解决方案
报错的直接原因是你向private表插入的ID_USER值为0,该值不存在于user表的主键列中,违反了外键约束规则,因此触发了报错。
你现有代码存在两处核心错误:
- 定义了user表的插入PreparedStatement后,没有执行就直接覆盖了pst变量为private表的插入语句,user表的插入逻辑完全没有实际运行
- 没有获取user表插入后自动生成的
ID_USER值,直接给private表写死了0作为ID_USER,自然不符合外键约束要求
正确实现步骤
- 插入user表时,指定PreparedStatement需要返回自动生成的主键
- 执行user表的插入操作后,提取生成的
ID_USER值 - 使用该
ID_USER作为参数执行private表的插入操作 - 增加事务控制,保证两次插入要么同时成功,要么同时失败,避免出现user表插入成功但private表插入失败的脏数据
修改后的代码如下:
private void insertarActionPerformed(java.awt.event.ActionEvent evt) { int val = 0; String user = jTextField_user.getText().trim(); String pass = jTextField_pass.getText().trim(); if (user.isBlank()) { val++; } if (pass.isBlank()) { val++; } if (val == 0) { Connection cn = null; PreparedStatement pstUser = null; PreparedStatement pstPrivate = null; try { cn = Conexion.conectar(); // 关闭自动提交,开启事务 cn.setAutoCommit(false); // 插入user表,指定返回自动生成的主键 pstUser = cn.prepareStatement( "Insert into user (USER) values (?)", Statement.RETURN_GENERATED_KEYS); // ID_USER是自增主键,不需要手动传值 pstUser.setString(1, user); pstUser.executeUpdate(); // 获取生成的ID_USER int generatedUserId = 0; ResultSet rs = pstUser.getGeneratedKeys(); if(rs.next()){ generatedUserId = rs.getInt(1); } // 插入private表,使用上面获取到的ID_USER pstPrivate = cn.prepareStatement( "Insert into private (ID_USER,PASSWORD) values(?,?)"); pstPrivate.setInt(1, generatedUserId); // 注意:生产环境请不要明文存储密码,需使用BCrypt等算法加密后存储 pstPrivate.setString(2, pass); pstPrivate.executeUpdate(); // 提交事务 cn.commit(); JOptionPane.showMessageDialog(null, "注册成功"); } catch (Exception e) { // 出现异常回滚事务 if(cn != null){ try { cn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } System.err.println("注册失败: " + e); } finally { // 依次关闭资源 if(pstUser != null){ try { pstUser.close(); } catch (SQLException e) { e.printStackTrace(); } } if(pstPrivate != null){ try { pstPrivate.close(); } catch (SQLException e) { e.printStackTrace(); } } if(cn != null){ try { cn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
注意事项
- 上述代码默认
ID_USER是user表的自增主键,因此插入user表时不需要给ID_USER传值,数据库会自动生成 - 生产环境绝对不要明文存储用户密码,必须使用BCrypt、PBKDF2等不可逆加密算法对密码进行哈希后再存入数据库
- 如果使用JDK7及以上版本,建议使用try-with-resources语法自动关闭连接、Statement等资源,代码会更简洁
内容的提问来源于stack exchange,提问作者wicked
相关产品推荐
相关产品推荐

