如何修复:嵌入式 H2 数据库“NonTransientError:无法读取所在位置的页面”错误?

Posted

技术标签:

【中文标题】如何修复:嵌入式 H2 数据库“NonTransientError:无法读取所在位置的页面”错误?【英文标题】:How to fix: Embedded H2 Database "NonTransientError: Unable to read the page at position" error? 【发布时间】:2020-02-15 14:00:48 【问题描述】:

我正在创建一个带有嵌入式 H2 数据库的 JavaFX 程序,该数据库将用于处理用户登录名和密码。使用 Intellij Ultimate,我有一个可以从工具栏运行的数据库。此外,我几乎可以肯定我拥有正确的 JDBC 驱动程序和 URL。该数据库在 Intellij 的数据库控制台上运行良好。当我尝试使用 Java 代码访问数据库时发生错误。我正在使用数据库类来处理我的数据库连接。

我收到JdbcSQLNonTransientException,一般错误:

非法状态异常:无法读取所在位置的页面

原因:java.lang.IllegalStateException: Unsupported type 17.

我的编译器中显示的导致错误的代码行: Connection conn = DriverManager.getConnection(DB_URL, "sa", "");

我已经尝试在任何地方找到类似的问题,但找不到相关问题。我已经尝试尽可能简化我的课程以隔离问题并简单地建立连接。我删除了我的项目并尝试重新开始。

产生问题的简化DatabaseManager 类:

public class DatabaseManager 
    static final String JDBC_DRIVER = "org.h2.Driver";
    static final String DB_URL = "jdbc:h2:D:/trant/Documents/Java Practice/Order A Car2/res/userDatabase";

    public static void main(String[] args) throws ClassNotFoundException, SQLException 
        Class.forName("org.h2.Driver");
        Connection conn = DriverManager.getConnection(DB_URL, "sa", "");
        Statement st = conn.createStatement();
        st.executeUpdate("SELECT * FROM JOBS");
        conn.close();
    

我希望连接到 H2 数据库并从表“JOBS”中检索数据。代码未编译并出现上述错误。

编辑:如果我使用 H2 的 1.4.199 版本而不是 1.4.200,问题就会消失。我在这里发现了一个几乎相同的问题:https://github.com/h2database/h2database/issues/2078。此链接与我的具有相同的堆栈跟踪。我还没有解决版本1.4.200的问题

【问题讨论】:

【参考方案1】:

https://github.com/h2database/h2database/issues/2078 您应该使用相同的驱动程序,因此在使用 1.4.196(IDEA 使用)进行修改后,无法使用 1.4.200(当前 spring 数据版本)读取它。所以我的崩溃场景是在 IDEA 中使用驱动程序 1.4.196 打开数据库,而 Spring 应用程序代码使用 1.4.200。所以它不会重新开始。您可以在 pom.xml 中为您的应用声明 1.4.196 版本,但看起来您将受限于此版本,我不知道如何完全修复您的数据库。

【讨论】:

【参考方案2】:

正如@Yura 所述,您需要确保所有代码库和所有工具都使用相同版本的驱动程序,无论是 1.4.196 还是 1.4.200。

接下来,如果你的 db 中没有任何有价值的东西,你可以安全地删除 db 文件,它会被重新创建。

如果你有一些有价值的数据而你没有备份,那么修复数据库可能成为一个任务,不一定成功......

如果您有备份,那么“backup-to-sql-using-196”和“restore-from-sql-using-200”程序最有可能为您完成这项工作,请参阅@987654321 @...

【讨论】:

这解决了我的问题。我们使用 h2 进行测试,并且没有数据如此简单,删除 /target/h2/ 文件夹中的 *.mv.db 文件解决了异常并在下次测试运行时正确重新创建了 db 我不知道为什么,但是删除数据库文件为我解决了这个问题。【参考方案3】:

首先,您必须将数据库副本保存在安全的地方。

将新副本复制到您的项目以避免任何损坏,请确保您不要尝试使用 inteliJ 打开它。

转到数据源和驱动程序 -> 驱动程序 -> H2 -> 驱动程序文件,将其更改为 1.4.196。 创建 h2 类型的新数据源并填写字段

用户:“sa”

密码:“”(空)

url 采用这种形式(数据库文件的路径)

jdbc:h2:file:D:\Downloads\loans\loans\Database

然后点击测试连接,它应该会显示一条绿色消息。应用并关闭。

在编辑器的数据库视图中右键单击您的数据库,然后“打开查询控制台”。运行此行(链接您要转储数据库的位置)

SCRIPT TO 'D:\Downloads\loans\loans\db-dump.sql'

新建一个数据库文件(Test.mv.database),按照前面的步骤,将驱动版本改回1.4.200。这次用相同的步骤创建一个新的数据源链接到你的新数据库

 jdbc:h2:file:D:\Downloads\loans\loans\Test

测试连接,应用并关闭。

打开查询控制台并从 db-dump.sql 复制粘贴脚本并运行它。在数据库视图中右键单击数据库,然后单击“刷新”。你应该看到数据。再次右键单击并单击“断开连接”。

确保您的 application.properties 文件指向正确的数据库(测试)并运行您的应用程序。

【讨论】:

【参考方案4】:

您确实应该提供完整的堆栈跟踪,而不仅仅是此类问题中的错误消息。

您看到的消息不是编译错误。

通常这样的消息意味着您的数据库已损坏。如果您不需要其中的任何数据,您只需删除其所有文件并从头开始重新创建即可。

如果您可以从某些工具打开数据库,但无法从您的应用程序打开它,请检查两个地方使用的 H2 版本并对齐它们。您可以使用SCRIPT TO 'filename.sql' 命令将数据库以适用于 SQL 脚本的版本导出,并使用该脚本将数据填充到新数据库中,以确保它没有损坏(使用您喜欢的版本)。

【讨论】:

堆栈跟踪到底是什么意思?另外,数据库怎么可能损坏?我刚刚开始了一个新项目,将驱动程序添加到项目结构下的依赖项中,并编写了一些代码。 从字面上看是堆栈跟踪,您可以自己搜索该术语。查看 Run 选项卡或 IDE 中的任何内容,您应该会看到 Exception …JdbcSQLNonTransientException… 和一些带有 at org.h2… 的行等等。我认为使用数据库并不是编程教育的最佳首选。我假设您已经以某种方式创建了一个数据库,如果您使用不同版本的 H2 可能是版本之间的不兼容,但您也可能以不同的方式获得损坏。 我更具体地询问堆栈跟踪的哪一部分。整个东西?这不是我第一次学习编程,谢谢。我认为该错误是由于 IntelliJ 数据库工具与与数据库连接的嵌入式代码之间的某种关系而发生的。当我删除数据库时,我的DatabaseManager 类将成功运行,这与您提到的损坏情况类似。 如果您的应用程序无法打开该工具后能够打开数据库,我建议您再次检查该工具和您的应用程序的类路径中包含的H2版本。旧版本的 H2 有时可能会写入和读取错误的页面。【参考方案5】:

我已经重现了同样的问题:

java.lang.IllegalStateException: Unable to read the page at position

同时使用Data Source 通过连接URL 连接到H2 db:

jdbc:h2:file:./data/testdb;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE

使用依赖:

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.197</version>
    </dependency>

经过一番调查发现问题:

Data Source 设置中使用的H2 驱动程序的版本重现了此错误(起初,这里是1.4.197):

特别是Data Source and Drivers -> Drivers -> H2 -> Driver files

解决方案:

    所以,首先,我换了另一个更新版本的1.4.200 H2 驱动:

    其次,我将POM中的依赖版本改为:

     <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
         <version>1.4.200</version>
     </dependency>
    

    第三,用相同的连接URL完全重新创建Data Source配置:

jdbc:h2:file:./data/testdb;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE

删除旧驱动程序的Data Base文件(新连接后会重新生成):

    Data Source 使用新驱动程序重新配置后,检查连接,结果它对我有用:

【讨论】:

【参考方案6】:

如果您不想更改 pom 或更改 h2 版本,请尝试删除文件:

    userDatabase.mv.db userDatabase.trace.db

您可以在目录“D:/trant/Documents/Java Practice/Order A Car2/res/”中找到这些文件。 但在删除之前确保没有从其他任何地方到数据库的活动连接。如果不确定,请在重新启动机器后立即删除。

完成后,再次尝试运行代码。这些文件将由 pom 重新生成

【讨论】:

【参考方案7】:

首先启动您的 h2 数据库,然后启动您的应用程序。

【讨论】:

以上是关于如何修复:嵌入式 H2 数据库“NonTransientError:无法读取所在位置的页面”错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复数据转换错误:jdbcTemplate.update,将 Enum 写入 H2 数据库

如何使用 H2 嵌入式数据库获取序列中的下一个值?

如何在 Mockito 单元测试期间生成 H2 嵌入式数据库?

如何嵌入 H2 数据库

如何使用嵌入式数据库 H2 创建 jar 文件?

如何使用 Gluon 在 Android 平台上将 H2 数据库连接为嵌入式模式?