【问题标题】:Bogus data in ResultSetResultSet 中的虚假数据
【发布时间】:2018-04-20 00:01:51
【问题描述】:

我在使用 JDBC 的 ResultSet 方面遇到了一些问题。

这是我的关系:

create table person (
person_id   number(5) generated always as identity
            minvalue 1
            maxvalue 99999
            increment by 1 start with 1
            cycle
            cache 10,
firstname   varchar(10) not null,
lastname    varchar(10) not null,
);

我正在尝试将 (firstname, lastname) 插入到元组中,然后获取从中产生的 person_id。这是我的 JDBC 代码:

//connection is taken care of beforehand and is named con
prep = con.prepareStatement("insert into person (firstname, lastname) values (?, ?)", Statement.RETURN_GENERATED_KEYS);
        prep.setString(1, firstname);
        prep.setString(2, lastname);
        prep.execute();
        ResultSet generated = prep.getGeneratedKeys();
        if (generated.next()) {
            String key = generated.getString("0");
            System.out.println(key);
        }

这一切正常。但我的问题是密钥应该是整数,而不是字符串。每次我运行它时,我都会得到一个包含“AAA3vaAAGAAAFwbAAG”字符串或类似内容的结果集。我想获取 person_id,以便稍后在我的 Java 程序中使用它。

在搜索 ResultSet 或执行语句本身时,我做错了什么吗?

【问题讨论】:

  • 为什么generated.getString("0") 会返回任何有意义的东西?
  • 我的印象是它检索到了ResultSet中唯一的一条数据。首先,我没有尝试过真正从对象中获取某些东西的方法,所以这就是我解决的问题。
  • 你用的是什么数据库?
  • 我正在使用使用我在本地创建的关系的自定义数据库。
  • @GregoryCheng 不,您使用的是什么数据库引擎?甲骨文?

标签: java database oracle jdbc resultset


【解决方案1】:

tl;博士

int id = generated.getInt( 1 ) ;

详情

您的问题似乎很困惑。

ResultSet 上的每个 get… 方法有两种形式。

  • 传递一个列号(int
  • 传递列名(String

你似乎把这两者结合成了:

String key = generated.getString("0") ;

我怀疑您是否有一个以单个数字零命名的列。除了名称选择不佳之外,标准 SQL 还禁止以数字开头的标识符。

所以这条线没有意义。也许您的意思是使用零 0 并错误地将其包裹在引号中的第一列,从而将您的预期 int 转换为实际的 String

即使这样的意图也是错误的。 ResultSet::getString 文档错误地将 int 描述为“columnIndex”。通常“索引”表示从零开始的计数偏移量。但实际上ResultSet::getString( int ) 要求您传递一个从一开始计数的序数。所以getString( 0 ) 永远无效。

因此,如果您想以文本形式检索结果集第一列的值,请执行以下操作:

String key = generated.getString( 1 ) ; // Retrieve first column of result set as text.

再一次,这在您的代码上下文中是错误的。您显然是在尝试检索在INSERT 期间生成的主键值。您的主键列person_id 定义为number(5),它不是文本类型。所以检索为String 是不合适的。

NUMBER(5) 不是标准 SQL。如果您碰巧使用的是 Oracle 数据库,the doc says 将是一个精度为 5 的整数类型,即最多为 5 位的数字。因此,通过调用 ResultSet::getInt 将其检索为 Java 中的整数类型。

int id = generated.getInt( 1 ) ;  // Retrieve the new row’s ID from the first column of the result set of generated key values returned by the `INSERT` prepared statement.

我上面的 cmets 一般用于数据库。但对于 Oracle,请参阅 Answer by Mark Rotteveel,说明 Oracle 数据库在调用 getGeneratedKeys 时确实返回生成的序列号。相反,它返回ROWID pseudo-column

【讨论】:

  • 可能也不是字符串。
  • @shmosel 是的,我现在看到了,回头看看代码要求生成主键值的事实。感谢你们在这里和问题上的帮助。我只是按照你的领导写这个答案。 :-)
  • 这就是我的主要问题。我最初有int id = generated.getInt( 1 ) ;,但后来我遇到了“无效转换”SQLException。
  • 在 OP 的情况下,这将不起作用,因为他使用的是 Oracle,并且生成的密钥默认返回 ROWID,而不是生成的标识符。
【解决方案2】:

您的问题是 Oracle 默认返回插入记录的 ROWID,而不是生成的标识符。来自Oracle JDBC Developer's Guide: Retrieval of Auto-Generated Keys

如果没有明确指出关键列,那么 Oracle JDBC 驱动程序 无法识别需要检索哪些列。当一个列名 或使用列索引数组,Oracle JDBC 驱动程序可以识别哪个 列包含您要检索的自动生成的键。 但是,当Statement.RETURN_GENERATED_KEYS 整数标志为 使用时,Oracle JDBC 驱动程序无法识别这些列。当。。。的时候 整数标志用于指示自动生成的键是 返回时,ROWID 伪列作为键返回。 ROWID 然后可以从ResultSet 对象中获取,并可用于 检索其他列。

因此,如果您使用Statement.RETURN_GENERATED_KEYS,您将获得ROWID,然后您可以使用该ROWID 选择插入的行以获取其他值(包括生成的标识符)。

如果您想专门检索生成的 id,对于 Oracle,您需要明确要求该列,如下所示:

String[] columns = { "PERSON_ID" }
prep = con.prepareStatement(
        "insert into person (firstname, lastname) values (?, ?)", columns);
prep.setString(1, firstname);
prep.setString(2, lastname);
prep.executeUpdate();
ResultSet generated = prep.getGeneratedKeys();
if (generated.next()) {
    int key = generated.getInt("PERSON_ID");
    System.out.println(key);
}

【讨论】:

    猜你喜欢
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    相关资源
    最近更新 更多