运行H2恢复脚本报错[42000-200],如何从损坏的H2数据库中提取数据
H2数据库Chunk丢失损坏数据恢复方案
你遇到的java.lang.IllegalStateException: Chunk 1936 not found [1.4.200/9]错误是H2的MVStore存储引擎的存储块损坏导致,第二步执行抛出的42000语法错误有两个可能原因:一是Recover工具导出的脚本里包含损坏块生成的非法SQL语句,直接执行触发解析错误后全量回滚;二是你命令里的URL用了中文引号,导致参数解析异常。最终得到空库是因为错误触发执行中断,已导入数据全部回滚。
可按以下优先级尝试恢复:
方案1:添加忽略错误参数执行导入
- 先保留你第一步生成的
xxx.mv.txt脚本文件 - 替换命令中的中文引号,新增
-continueOnError参数重新执行RunScript:
java -cp h2*.jar org.h2.tools.RunScript -url jdbc:h2:file:~/tmp/recovery -user user -password password -script file_generated_by_previous_step.mv.txt -showResults -continueOnError
- 这个参数会跳过所有语法错误的损坏块语句,不会终止执行,大部分完好的表数据都会正常导入到新库中
方案2:导出脚本时直接跳过损坏块
如果方案1恢复的数据量很少,重新生成剔除损坏块的脚本:
- 执行带过滤参数的Recover命令:
java -cp h2*.jar org.h2.tools.Recover -dir [损坏数据库所在目录路径] -db [损坏数据库的名称] -transactionLog false -skipBadChunks true
- 这个命令会在导出阶段就直接跳过所有识别为损坏的块,生成的脚本不会包含非法SQL,再正常执行RunScript导入即可
方案3:直接读取MVStore文件提取原始数据
如果前两种方案都无法恢复核心数据,可以用H2原生API直接读取存储文件中的完好页数据:
import org.h2.mvstore.MVStore; import org.h2.mvstore.MVMap; public class H2RawRecover { public static void main(String[] args) { // 路径替换为你的损坏数据库文件路径,不要加.mv.db后缀 MVStore store = MVStore.openReadOnly("/path/to/your/database/name"); // 遍历所有存储的表数据映射 for (String mapName : store.getMapNames()) { MVMap<Object, Object> dataMap = store.openMap(mapName); System.out.println("表映射名:" + mapName + ",有效数据条数:" + dataMap.size()); // 可自行扩展代码,将遍历到的数据导出为CSV或者插入新库 for (var entry : dataMap.entrySet()) { System.out.println(entry.getKey() + " = " + entry.getValue()); } } store.close(); } }
注意:执行上述代码时,依赖的H2 Jar包版本必须和你原数据库使用的版本完全一致,否则会出现兼容性问题读不到数据
后续建议
恢复完数据后立刻做全量备份,你使用的1.4.200版本存在多个已知的MVStore损坏漏洞,如果业务允许建议升级到2.x稳定版,降低后续损坏概率。
内容的提问来源于stack exchange,提问作者Alex Pogorelov
相关产品推荐
相关产品推荐

