H2 数据库结果集是只读的

H2 Database result set is readonly

我在尝试更新 H2 数据库中的某一行时遇到 SQLNonTransientException 错误。

public static void setNewServiceInformationsToShown() {
    try (Connection conn = DriverManager.getConnection("jdbc:h2:" + Main.config_db_location,
            Main.config_db_username, Main.config_db_password)) {
        //read data from database
        PreparedStatement stmt = conn.prepareStatement("SELECT * FROM BCSTASKS_SERVICE");
        
        ResultSet rs = stmt.executeQuery();
        while (rs.next()) {
            if(rs.getString("Status").equals("Neu") && rs.getBoolean("wasShown") == false) {
                rs.updateBoolean("WASSHOWN", true);
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

错误消息已经建议我应该使用 conn.createStatement 并将 ResultSet 设置为 CONCUR_UPDATABLE。错误发生在 rs.updateBoolean(...);

错误信息:

The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). [90140-210]

问题是我不知道应该在哪里以及如何使用这个方法。在同一个函数中还是在程序的开头?

您需要为更新创建单独的 query/prepareStatement。据我所知,就您而言,您只需要一个更新查询:

conn.prepareStatement("UPDATE BCSTASKS_SERVICE SET WASSHOWN=true where 
                       Status = 'Neu' and wasShown = false "

您必须在数据库中对更新数据进行更新查询,但您正在使用 select 查询,这就是问题所在。

  • Select 如果您必须从数据库中获取数据,则使用查询。
  • Update查询用于更新数据库中的数据,其中数据已存储在数据库中,但您只是覆盖数据。

下面是修改后的代码:

public static void setNewServiceInformationsToShown() {
    try (Connection conn = DriverManager.getConnection("jdbc:h2:" + Main.config_db_location,
            Main.config_db_username, Main.config_db_password)) {
        PreparedStatement stmt = conn.prepareStatement("UPDATE BCSTASKS_SERVICE SET wasShown = ? WHERE status = ? AND wasShown = ?");     
        stmt.setBoolean(1, true);
        stmt.setString(2, "Neu");
        stmt.setBoolean(3, false);
        stmt.executeUpdate();
        stmt.close();
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

我看到的大多数数据库代码都不会尝试使用结果集可更新这一事实,而是会触发一个额外的 UPDATE 查询,该查询工作正常。

但是,当然,H2 也支持可更新的结果集。然而,ResultSets 的一些特性实际上有相当大的成本;数据库引擎需要做大量额外的簿记工作以启用具有性能成本的此类功能。许多数据库查询对性能极为敏感,因此默认情况下您 不会 进行簿记,因此这些功能不起作用。您需要明确启用它们,这就是错误告诉您的内容。

您当前正在调用 'wrong' preparedStatement 方法。你想要更扩展的一个,你可以在其中选择你希望 H2 为你做的额外簿记,以实现这些功能。你想要 this one.


conn.prepareStatement(
  "SELECT * FROM BCSTASKS_SERVICE",
  ResultSet.TYPE_SCROLL_INSENSITIVE, // [edited]
  ResultSet.CONCUR_UPDATABLE);

那个 CONCUR_UPDATABLE 东西只是你传递的一个标志:请记账,以便我可以调用 .update

[edited] 这以前曾读过 0,但正如@MarkRotteveel 指出的那样,根据文档,这是无效的。