为什么我们在 NamedParameterJDBCTemplate 中获取 keyholder 值时添加新的 String[]{"ID"}

问题描述

在 NamedParameterJDBCTemplate 中获取 keyholder 值时为什么要添加 new String[]{"ID"}

我的问题是基于这个问题的答案: Is there a way to extract primary key(or ROWID) using NamedParameterJdbcTemplate and GeneratedKeyHolder?

我的问题可能听起来很愚蠢,但我确实需要对此进行澄清。 我知道,尝试使用 Keyholder 从 DB 获取 PK 时出现异常的解决方案:生成的密钥不是受支持的数字类型。无法将 [oracle.sql.ROWID] 转换为 [java.lang.Number]

我的问题为什么我们将 ID 转换为字符串数组,然后获取它的 long 值?不能直接获取long值吗?

有关代码片段,请参阅上述链接中的答案。我的问题是基于答案。

解决方法

默认情况下,Spring 的 JdbcTemplate 会使用 JDBC 的 Statement.RETURN_GENERATED_KEYS 选项。问题是 Oracle JDBC 驱动程序不会返回该选项的 id 列的值,而是返回“行 id”(基本上是指向行的内部指针,而不是该行中的 id 值)。这不适用于大多数用例,因为它需要您使用行 id 显式查询行以获取实际 id 值,特别是在 Spring 的 KeyHolder 的实现中会导致上述错误,因为 {{1 }} 实现不是很长(也不是 java.sql.RowId 的子类)。

幸运的是,JDBC 提供了其他方法来获取生成的列:通过显式指定您想要的列的列名(或列索引)。这就是 java.lang.Number 所做的。它指示 JdbcTemplate 将此列名数组传递给 JDBC 驱动程序,驱动程序(假设它支持此功能)将返回指定的列,即如果您的表实际上有一个名为 {{1} 的列}.

换句话说,这不会“将 ID 转换为字符串数组然后获取其长值”,它将检索列 new String[] {"ID"} 的值而不是 Oracle JDBC返回插入行的“行 ID”的驱动程序。

您链接的问题专门针对 Oracle(默认返回行 ID)。 Oracle JDBC 驱动程序返回行 ID 的原因是因为直到最近 Oracle 还没有标识列,并且具有类似标识的行为的唯一方法是使用自定义触发器来生成 ID。这使得无法确定表是否生成了列,以及如果生成了哪些列。相反,除非指定了显式列,否则实现决策是返回行 ID。

虽然这个问题是 Oracle 特有的,但其他驱动程序可能有不同的问题,可能需要使用相同的解决方案来解决:例如某些驱动程序(例如 PostgreSQL 和 Firebird(Jaybird,我维护的 Firebird JDBC 驱动程序))将默认返回所有列,如果您的 ID 列不是第一列,这可能会导致类似的错误,因为 Spring ID 方法假定生成的 id 保存在生成​​的键结果集的第一列中。>