H2数据库损坏恢复
0.前言
今天登录博客,发现首页报错,想着去后台重启下看看,发现服务器启动不起来了,报了一个如下的错误:
1 org.h2.jdbc.JdbcSQLNonTransientConnectionException: File corrupted while reading record: null. Possible solution: use the recovery tool [90030-199] 2 at org.h2.message.DbException.getJdbcSQLException(DbException.java:617) ~[h2-1.4.199.jar!/:na] 3 at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) ~[h2-1.4.199.jar!/:na] 4 at org.h2.message.DbException.get(DbException.java:194) ~[h2-1.4.199.jar!/:na] 5 at org.h2.mvstore.db.MVTableEngine$Store.convertIllegalStateException(MVTableEngine.java:205) ~[h2-1.4.199.jar!/:na] 6 at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:173) ~[h2-1.4.199.jar!/:na] 7 at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:95) ~[h2-1.4.199.jar!/:na] 8 at org.h2.engine.Database.getPageStore(Database.java:2739) ~[h2-1.4.199.jar!/:na] 9 at org.h2.engine.Database.open(Database.java:769) ~[h2-1.4.199.jar!/:na] 10 at org.h2.engine.Database.openDatabase(Database.java:319) ~[h2-1.4.199.jar!/:na] 11 at org.h2.engine.Database.<init>(Database.java:313) ~[h2-1.4.199.jar!/:na] 12 at org.h2.engine.Engine.openSession(Engine.java:69) ~[h2-1.4.199.jar!/:na] 13 at org.h2.engine.Engine.openSession(Engine.java:201) ~[h2-1.4.199.jar!/:na] 14 at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178) ~[h2-1.4.199.jar!/:na] 15 at org.h2.engine.Engine.createSession(Engine.java:161) ~[h2-1.4.199.jar!/:na] 16 at org.h2.engine.Engine.createSession(Engine.java:31) ~[h2-1.4.199.jar!/:na] 17 at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:336) ~[h2-1.4.199.jar!/:na] 18 at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:169) ~[h2-1.4.199.jar!/:na] 19 at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:148) ~[h2-1.4.199.jar!/:na] 20 at org.h2.Driver.connect(Driver.java:69) ~[h2-1.4.199.jar!/:na] 21 ......省略号...... 22 Caused by: java.lang.IllegalStateException: File corrupted in chunk 1198302, expected page length 4..1024, got 976302644 [1.4.199/6] 23 at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) ~[h2-1.4.199.jar!/:na] 24 at org.h2.mvstore.MVStore.readBufferForPage(MVStore.java:1055) ~[h2-1.4.199.jar!/:na] 25 at org.h2.mvstore.MVStore.readPage(MVStore.java:2186) ~[h2-1.4.199.jar!/:na] 26 at org.h2.mvstore.MVMap.readPage(MVMap.java:554) ~[h2-1.4.199.jar!/:na] 27 at org.h2.mvstore.Page$NonLeaf.getChildPage(Page.java:1086) ~[h2-1.4.199.jar!/:na] 28 at org.h2.mvstore.Cursor.hasNext(Cursor.java:53) ~[h2-1.4.199.jar!/:na] 29 at org.h2.mvstore.MVStore.readStoreHeader(MVStore.java:793) ~[h2-1.4.199.jar!/:na] 30 at org.h2.mvstore.MVStore.<init>(MVStore.java:401) ~[h2-1.4.199.jar!/:na] 31 at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) ~[h2-1.4.199.jar!/:na] 32 at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:162) ~[h2-1.4.199.jar!/:na] 33 ... 139 common frames omitted
心想,坏了卧槽,数据库文件坏了。
1.找恢复工具
H2官方就提供恢复工具,地址:https://www.h2database.com/html/download-archive.html ,找到合适的版本,由于我的H2用的版本是1.4.199的版本,下载那个 Platform-Independent Zip 就行了,如下图:

3.数据提取
3.1解压下载好的ZIP到本地目录,如 h2Recover,自己记得就行,目录层级应该如下:
h2Recover - h2 - bin - h2.bat - h2.sh - h2-1.4.199.jar - h2w.bat + src + docs + service build.bat build.sh
我们需要的就是bin/h2-1.4.199.jar的这个文件
3.2找到你损坏的数据库文件,以*.mv.db结尾的那个文件,复制到 bin 目录下
3.3执行以下命令进行数据提取
java -cp h2-1.4.199.jar org.h2.tools.Recover
jar包会自动找到当前目录下的db文件,然后生成对应的数据恢复脚本。
4.意外
不出意外的话就要出现意外了,就知道没有这么的顺利,恢复工具报了一个和启动一样的错误:
1 Exception in thread "main" java.lang.IllegalStateException: File corrupted in chunk 1198302, expected page length 4..1024, got 976302644 [1.4.199/6] 2 at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883) 3 at org.h2.mvstore.MVStore.readBufferForPage(MVStore.java:1055) 4 at org.h2.mvstore.MVStore.readPage(MVStore.java:2186) 5 at org.h2.mvstore.MVMap.readPage(MVMap.java:554) 6 at org.h2.mvstore.Page$NonLeaf.getChildPage(Page.java:1086) 7 at org.h2.mvstore.Cursor.hasNext(Cursor.java:53) 8 at org.h2.mvstore.MVStore.readStoreHeader(MVStore.java:793) 9 at org.h2.mvstore.MVStore.<init>(MVStore.java:401) 10 at org.h2.mvstore.MVStore$Builder.open(MVStore.java:3343) 11 at org.h2.mvstore.MVStoreTool.info(MVStoreTool.java:347) 12 at org.h2.tools.Recover.process(Recover.java:344) 13 at org.h2.tools.Recover.runTool(Recover.java:195) 14 at org.h2.tools.Recover.main(Recover.java:158)
5.上Google
最后发现也有人在使用恢复工具的时候出现过同样的问题,甚至版本都一样的199,然后他发布了解决办法,详见 https://github.com/h2database/h2database/issues/2139 ,

有个小伙纸他说他提取数据时用的是 1.4.196 的版本,恢复时再换回的 1.4.199 的版本,互联网上有才的人和好人还是多的啊。
遂在下了一个 1.4.196 的恢复工具,重新执行了第 3.3 步骤中的数据提取命令。居然可以了,会生成一个和你的库同名的 xx.h2.sql的文件,只是。。。。我一个平常备份也就是二三十M的DB文件,提取完成后的恢复脚本居然高达7个多G。先不管了,恢复数据看看先。。
6.数据还原
原先被损坏的库先行备份、先行备份、先行备份,以免出错,然后执行以下命令,生成一个全新的数据库:
java -cp h2-1.4.199.jar org.h2.tools.RunScript -url jdbc:h2:./xxx -user username -password password -script xxx.h2.sql
其中的 xxx 就是你库的名称。username是库的用户名。password是库的密码,稍等一会,等待数据重新导入完成。
7.后续
数据库导入完成后,7G的脚本生成了一个3G多的库肯定是不行的,其实解决办法也很简单。找个数据库连接工具,比如DBEAVER,链接到你的库。然后随便打开某个表。改个字段值。保存,关闭库。你就会发现库缩小回正常的体积了。
然后把库放回到项目里重新启动,发现正常,由于我的项目更新频次很低,应该是主要数据都没有丢,如果你们项目使用频次数据更新频次很高,应该还是会丢失一部分数据的,但能恢复极大部分数据,已经可以了。后续多多备份吧。
8.参考
浙公网安备 33010602011771号