我想在循环遍历结果集时更新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节 的信息。
答案 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_ONLY
和CONCUR_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