ResultSet更新行无效

时间:2015-01-24 10:17:34

标签: java mysql jdbc

我想在循环遍历结果集时更新ResultSet中的raw。以下是我的代码

try {
    String query="SELECT * FROM smsmessage WHERE recipient = ? and sent_status = 'pending' LIMIT ? ";
PreparedStatement prepStmt = conn.prepareStatement(query);
    prepStmt.setString(1,shortCode);
    prepStmt.setInt(2, Integer.parseInt(batchSize));
    ResultSet rs=prepStmt.executeQuery();
    while (rs.next()) {

        //update the selected message sent status to "sent" from "pending"
        rs.updateString("sent_status","sent");
        rs.updateRow();
    }

} catch (SQLException e) {
    log.error("MySQL exception",e);
}

这可能是什么原因?

我收到以下错误

  

com.mysql.jdbc.NotUpdatable:结果集不可更新。这个结果集   必须来自使用结果集类型创建的语句   ResultSet.CONCUR_UPDATABLE,查询必须只选择一个表,才可以   不使用函数,必须从该表中选择所有主键。   有关更多详细信息,请参阅JDBC 2.1 API规范,第5.6节。这个   结果集必须来自使用结果创建的语句   设置ResultSet.CONCUR_UPDATABLE的类型,查询必须只选择一个   表,不能使用函数,必须从中选择所有主键   那张桌子。有关更多信息,请参阅JDBC 2.1 API规范,第5.6节   的信息。

2 个答案:

答案 0 :(得分:9)

那么,您应该首先仔细阅读错误文本:

  

com.mysql.jdbc.NotUpdatable:结果集不可更新。这个结果   set必须来自使用结果集创建的语句   类型ResultSet.CONCUR_UPDATABLE,查询必须只选择一个   表,不能使用函数,必须从中选择所有主键   那张桌子。有关更多信息,请参阅JDBC 2.1 API规范,第5.6节   的信息。

这意味着结果集不可更新。您无法更新无法更新的结果集。

它还表示此结果集必须来自使用结果集类型ResultSet.CONCUR_UPDATABLE创建的语句。这意味着您的声明(在本例中为PreparedStatement)必须使用该选项创建。

最后,它会引导您进入文档。 JDBC 2.1有点过时,您可以在通常的J2SE文档中找到所有相关数据。让我们从ResultSet的文档开始。它说:

  

默认的ResultSet对象不可更新,并且有一个游标   只向前迈进。因此,您只需迭代一次即可   仅从第一行到最后一行。有可能生产   可滚动和/或可更新的ResultSet对象。下列   代码片段,其中con是有效的Connection对象,说明了   如何创建可滚动且对更新不敏感的结果集   由其他人,这是可更新的。请参阅其他的ResultSet字段   选项。

它显示的代码片段是:

   Statement stmt = con.createStatement(
                                  ResultSet.TYPE_SCROLL_INSENSITIVE,
                                  ResultSet.CONCUR_UPDATABLE);
   ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
   // rs will be scrollable, will not show changes made by others,
   // and will be updatable

所以你看,他们正在使用一个语句,你可以在其中添加两个参数,使你可以滚动数据并更新它。但他们使用Statement而不是PreparedStatement。这也适用于PreparedStatement吗?

转到PreparedStatement文档对你没有多大帮助,但是等等,你正在使用连接对象来准备语句,也许它会对你有帮助吗?

是的,确实有一个method in Connection允许您传递参数,就像示例中的Statement一样。

PreparedStatement prepareStatement(String sql,
                                 int resultSetType,
                                 int resultSetConcurrency)
                                   throws SQLException

所以现在你必须问自己,我需要什么样的resultSetType,以及resultSetConcurrency是什么类型的?

当前问题不需要滚动语句,因此您可以使用默认语句。如果你看the documentation of the plain preparedStatement(String),你会看到:

  

使用返回的PreparedStatement对象创建的结果集将会   默认情况下是类型TYPE_FORWARD_ONLY并且具有并发级别   CONCUR_READ_ONLY。创建的结果集的可保持性可以是   通过致电getHoldability()确定。

...顺便说一句,这就是为什么你的初始准备语句不可更新的原因。但无论如何,它告诉你滚动类型的默认值是TYPE_FORWARD_ONLY

更新如何,这是重要的部分?好吧,选项是CONCUR_READ_ONLYCONCUR_UPDATABLE。所以你需要使用第二个。毕竟,这就是错误信息告诉你的内容。

结论:

您需要使用

PreparedStatement prepStmt = conn.prepareStatement(
                                  query,
                                  ResultSet.TYPE_FORWARD_ONLY,
                                  ResultSet.CONCUR_UPDATABLE);

这将为您提供可更新的结果集。

这就是如何从您收到的错误消息中找到答案。

答案 1 :(得分:8)

正如stacktrace所说,你必须创建一个允许其结果集可更新的语句:

PreparedStatement prepStmt= conn.prepareStatement(query,
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

来自ResultSet的API(http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html):

  

默认的ResultSet对象不可更新,并且只有一个向前移动的光标。因此,您只能迭代一次,并且只能从第一行到最后一行。可以生成可滚动和/或可更新的ResultSet对象。以下代码片段(其中con是有效的Connection对象)说明了如何使结果集可滚动且对其他人的更新不敏感,并且是可更新的。有关其他选项,请参阅ResultSet字段。

   Statement stmt = con.createStatement(
                                  ResultSet.TYPE_SCROLL_INSENSITIVE,
                                  ResultSet.CONCUR_UPDATABLE);
   ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
   // rs will be scrollable, will not show changes made by others,
   // and will be updatable