父表主键填充子表问题:customer主键无法插入address表咨询
问题原因分析
- 逻辑职责错位:当前
addAddress方法内每次都会调用addCustomer新增客户,既不符合「给已有客户新增地址」的场景,也没有和客户新增逻辑做事务绑定 - 自增主键插入写法存在兼容风险:主动给自增主键
customerId、addressId赋值为0,部分数据库严格模式下会直接触发主键冲突报错,导致插入失败 - 缺少事务控制:客户插入成功但地址插入失败时,已插入的客户数据不会回滚,产生脏数据
- 注意首先确认外键配置正确:
address表的customerId字段需设置外键关联customer表的customerId主键,同时开启ON DELETE CASCADE,这是级联删除生效的前提
修正方案
调整方法职责拆分,新增统一的事务方法处理「新增客户同时关联地址」的场景,修正自增主键的插入写法。
修正后的基础方法代码
/** * 新增客户 * @param customer 待新增的客户对象 * @return 生成的客户ID * @throws SQLException 数据库操作异常 */ public int addCustomer(Customer customer) throws SQLException { // 自增主键无需主动插入,由数据库自动生成 var sql = "INSERT INTO customer (customerName, active, createdBy) VALUES (?, ?, ?)"; var statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); statement.setString(1, customer.getName()); statement.setBoolean(2, customer.isActive()); statement.setString(3, customer.getCreatedBy()); statement.executeUpdate(); var generatedKeys = statement.getGeneratedKeys(); if(generatedKeys.next()) { return generatedKeys.getInt(1); } throw new SQLException("新增客户失败,未获取到生成的主键"); } /** * 新增地址 * @param address 待新增的地址对象 * @param customerId 关联的客户ID * @throws SQLException 数据库操作异常 */ public void addAddress(Address address, int customerId) throws SQLException { // 自增主键无需主动插入,由数据库自动生成 var sql = "INSERT INTO address (customerId, address, address2, cityId, countryId, postalCode, phone, createdBy) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; var statement = connection.prepareStatement(sql); statement.setInt(1, customerId); statement.setString(2, address.getAddress()); statement.setString(3, address.getAddress2()); statement.setInt(4, address.getCity().getId()); statement.setInt(5, address.getCountry().getId()); statement.setString(6, address.getPostalCode()); statement.setString(7, address.getPhone()); statement.setString(8, address.getCreatedBy()); statement.executeUpdate(); }
统一事务业务方法
新增统一方法处理新增客户带地址的场景,用事务保证两个操作的原子性:
/** * 新增客户同时关联新增对应地址 * @param customer 客户对象 * @param address 关联的地址对象 * @throws SQLException 数据库操作异常 */ public void addCustomerWithAddress(Customer customer, Address address) throws SQLException { try { // 关闭自动提交开启事务 connection.setAutoCommit(false); // 先插入客户获取生成的客户ID int customerId = addCustomer(customer); // 再插入关联地址 addAddress(address, customerId); // 全部操作成功提交事务 connection.commit(); } catch (SQLException e) { // 任意步骤失败回滚所有操作 connection.rollback(); throw e; } finally { // 恢复默认自动提交配置 connection.setAutoCommit(true); } }
其他注意事项
- 如果是给已有的客户新增地址,直接传入对应客户ID调用
addAddress方法即可,不需要重复新增客户 - 确认数据库表的自增配置开启:
customer表的customerId、address表的addressId需设置为自增主键 - 级联删除测试:删除
customer表的指定记录后,检查address表对应的关联记录是否自动删除,确认外键配置生效
内容的提问来源于stack exchange,提问作者kisimoh
相关产品推荐
相关产品推荐

