ResultSet update row is not working

2019-07-07 12:27发布

问题:

I want to update raw in my ResultSet while I looping through the result set. Following is my code

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);
}

What should be the possible reason for this?

I am getting following error

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.

回答1:

As the stacktrace tells, you have to create a statement that allows its resultset to be updateable:

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

From the API of ResultSet (http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html):

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


回答2:

Well, you should start by carefully reading the error text:

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 means that the result set is not updateable. You can't update a result set that is not updateable.

It also says that this result set must come from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE. This means that your statement - in this case a PreparedStatement, must be created with that option.

Finally, it directs you to the documentation. JDBC 2.1 is a bit outdated, and you can find all the relevant data in the usual J2SE Documentation. Let's start from the documentation for ResultSet. It says:

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.

And the code fragment it shows is:

   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

So you see, they are using a statement where you add two parameters, that enable you to scroll through the data and update it. But they are using a Statement rather than a PreparedStatement. Is this applicabe to PreparedStatement as well?

Going to the PreparedStatement documentation will not help you much, but wait, you are using the connection object to prepare the statement, perhaps it will help you?

Yes, indeed, there is a method in Connection that allows you to pass the parameters, just like the Statement in the example.

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

So now you must ask yourself, what kind of resultSetType do I need, and what kind of resultSetConcurrency?

Scrolling your statement is not necessary for your current question, so you can use the default. If you look at the documentation of the plain preparedStatement(String) you'll see:

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().

...which is why your initial prepared statement was not updatable, by the way. But anyway, it tells you that the default for the scrolling type is TYPE_FORWARD_ONLY.

What about the updating, which is the important part? Well, the options are CONCUR_READ_ONLY and CONCUR_UPDATABLE. So you need to use the second one. That's what the error message told you, after all.

Conclusion:

You need to use

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

This will give you an updatable result set.

And this is how to find your answer from the error message that you get.



标签: java mysql jdbc