重现 SQL 层架构中的异常和正确处理

Reproducing SQL Exception and correct handling in layer architecture

假设我有这个:

String sql = "DELETE FROM "+ TABLE_NAME +"  WHERE id=?";
       
try {
    int ra = jdbcTemplate.update(connection -> {
                PreparedStatement stmt = connection.prepareStatement(sql);
                stmt.setLong(1, id);
                stmt.executeUpdate();
                return stmt;
            });

    if (ra == 0)
        throw new SQLException(SQL_ERROR);
} catch (SQLException e){
    LOGGER.error(SQL_ERROR);
    throw new DataAccessLayerException("Entity could not be deleted due to SQL Exception");
}

我正在使用密钥 (id) 从 table 中删除一个实体。现在我希望能够向客户报告 INTERNAL_SERVER_ERROR 而不会导致 RuntimeException.

但是,我无法重现SQLException。例如,如果我在我的 sql 语句中删除一个字母,我只会收到一个作为运行时错误抛出的语法错误,而且我似乎没有捕捉到它。

帮助我理解这里 SQLException 的确切含义,以及如何在不导致 RuntimeException 的情况下重现它并将其报告给客户端?

您的代码有误。您正在呼叫 update(PreparedStatementCreator psc), and as the name suggests, your code should create a fully "prepared" statement object, but it should not "execute" that statement, so remove the executeUpdate() 呼叫。

update() 调用抛出 DataAccessException,而不是 SQLException,因此 try 块中 SQLException 的唯一来源是您的 if 语句,所以你最好直接抛出 DataAccessLayerException 异常。不过,我建议改用 EmptyResultDataAccessException

由于Spring专门将已检查的SQLException转换为未检查的DataAccessException运行时异常,所以使用SpringJDBC时总是会出现运行时异常,并且这是一件好事,因为您现在不需要向代码中的所有方法添加已检查的异常。

未处理的异常由 Spring MVC 处理。默认情况下,Spring MVC 将重定向到错误页面。如果你不想要那个,请参见例如问题 Spring Boot Remove Whitelabel Error Page.