如何修复:嵌入式 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 数据库