结果集更新行不起作用

ResultSet update row is not working

我想在遍历结果集时更新结果集中的原始数据。以下是我的代码

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: Result Set not updatable. This result set must come from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE, the query must select only one table, can not use functions and must select all primary keys from that table. See the JDBC 2.1 API Specification, section 5.6 for more details.This result set must come from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE, the query must select only one table, can not use functions and must select all primary keys from that table. See the JDBC 2.1 API Specification, section 5.6 for more details.

如堆栈跟踪所示,您必须创建一个允许其结果集可更新的语句:

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

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

A default ResultSet object is not updatable and has a cursor that moves forward only. Thus, you can iterate through it only once and only from the first row to the last row. It is possible to produce ResultSet objects that are scrollable and/or updatable. The following code fragment, in which con is a valid Connection object, illustrates how to make a result set that is scrollable and insensitive to updates by others, and that is updatable. See ResultSet fields for other options.

   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

嗯,你应该从仔细阅读错误文本开始:

com.mysql.jdbc.NotUpdatable: Result Set not updatable. This result set must come from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE, the query must select only one table, can not use functions and must select all primary keys from that table. See the JDBC 2.1 API Specification, section 5.6 for more details.

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

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

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

A default ResultSet object is not updatable and has a cursor that moves forward only. Thus, you can iterate through it only once and only from the first row to the last row. It is possible to produce ResultSet objects that are scrollable and/or updatable. The following code fragment, in which con is a valid Connection object, illustrates how to make a result set that is scrollable and insensitive to updates by others, and that is updatable. See ResultSet fields for other options.

它显示的代码片段是:

   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),您会看到:

Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have a concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling getHoldability().

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

更新呢,哪个是重要的部分?嗯,选项是 CONCUR_READ_ONLYCONCUR_UPDATABLE。所以你需要使用第二个。毕竟,这就是错误消息告诉您的内容。

结论:

你需要使用

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

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

这是从您收到的错误消息中找到答案的方法。