PostgreSQL执行DELETE语句后如何获取已删除记录的主键ID?
问题根因
- JDBC的
getGeneratedKeys()默认仅支持INSERT操作返回自增主键,DELETE操作不会默认填充该结果集。 - PostgreSQL需要在DELETE语句后添加
RETURNING子句才能显式返回被删除行的指定字段。 - 你创建
PreparedStatement时未指定需要返回的键字段,即使加了RETURNING也无法正常获取结果。
代码调整步骤
1. 修改删除表单的SQL语句
添加RETURNING id子句,指定删除后返回表单ID:
private static final String REMOVE_FORM = "DELETE FROM forms WHERE name = ? RETURNING id";
2. 调整PreparedStatement初始化逻辑
创建Statement时指定需要返回的ID列,确保返回结果可以被正常获取:
public boolean connect() throws SQLException{ this.connection = DriverManager.getConnection(URL); // 指定返回id列,也可以用Statement.RETURN_GENERATED_KEYS参数替代列名数组 this.removeFormQuery = this.connection.prepareStatement(REMOVE_FORM, new String[]{"id"}); }
如果后续删除字段、删除字段值的逻辑也需要获取被删ID,对应SQL和PreparedStatement初始化也需要按照上面的逻辑同步修改
3. 调整删除逻辑,修正结果判断的问题
你原有逻辑中用execute()的返回值判断执行结果容易出错,推荐用executeQuery()直接获取删除返回的ID集,用executeUpdate()的返回影响行数判断执行是否成功:
private void removeForm(String form) { try { removeFormQuery.setString(1, form); // 直接执行查询获取被删表单的ID ResultSet deletedFormIds = removeFormQuery.executeQuery(); while (deletedFormIds.next()) { int formId = deletedFormIds.getInt("id"); removeFieldQuery.setInt(1, formId); int fieldAffected = removeFieldQuery.executeUpdate(); if (fieldAffected <= 0) { System.out.println("remove field failed"); continue; } System.out.println("remove field success"); ResultSet deletedFieldIds = removeFieldQuery.getGeneratedKeys(); while (deletedFieldIds.next()) { int fieldId = deletedFieldIds.getInt("id"); removeListItemQuery.setInt(1, fieldId); int itemAffected = removeListItemQuery.executeUpdate(); System.out.println(itemAffected > 0 ? "remove listItem success" : "remove listItem failed"); } } } catch (SQLException e) { e.printStackTrace(); } }
更优方案(推荐)
不需要在代码中循环关联删除,直接在数据库层配置外键级联删除即可:
- 给第二张表的
form_id字段添加外键关联forms.id,设置ON DELETE CASCADE - 给第三张表的
field_id字段添加外键关联第二张表的主键,设置ON DELETE CASCADE
配置完成后,只要删除forms表的对应记录,数据库会自动删除所有关联的字段和字段值数据,无需额外的Java代码,执行效率更高也不会出现关联遗漏问题。
内容的提问来源于stack exchange,提问作者Leboroz
相关产品推荐
相关产品推荐

