使用JPA操作H2数据库时如何获取MVStore实例
JPA环境下通过EntityManager访问H2 MVStore组件实现方法
适用范围:H2 1.4.x及以上版本、JDBC连接参数已开启
MV_STORE=TRUE(H2高版本默认开启)
实现步骤
所有操作必须在活跃事务上下文内执行,否则解包连接、访问内部组件会抛出权限或状态异常。
- 从EntityManager解包获取H2原生JDBC连接
JPA的EntityManager是上层抽象,需要逐层解包跳过JPA实现、连接池的代理对象,最终拿到H2自带的JdbcConnection实例:
EntityTransaction tx = em.getTransaction(); boolean manualTx = false; // 无活跃事务时手动开启事务 if (!tx.isActive()) { tx.begin(); manualTx = true; } // 先解包出基础JDBC连接 java.sql.Connection baseConn = em.unwrap(java.sql.Connection.class); // 循环解包穿透连接池代理,直到拿到H2原生连接 while (baseConn.isWrapperFor(org.h2.jdbc.JdbcConnection.class)) { baseConn = baseConn.unwrap(org.h2.jdbc.JdbcConnection.class); } org.h2.jdbc.JdbcConnection h2Conn = (org.h2.jdbc.JdbcConnection) baseConn;
- 从H2原生连接提取MVStore实例
通过H2连接获取内部Session、Database对象,最终拿到MVStore核心组件:
org.h2.engine.Session h2Session = (org.h2.engine.Session) h2Conn.getSession(); org.h2.mvstore.MVStore mvStore = h2Session.getDatabase().getMvStore(); // 校验MVStore实例,未开启MVStore引擎时会返回null if (mvStore == null) { if (manualTx) tx.rollback(); throw new IllegalStateException("当前H2实例未启用MVStore引擎,请在JDBC URL添加MV_STORE=TRUE参数"); }
- 调用MVStore原生方法
拿到MVStore实例后即可直接调用你需要的底层操作:
// 执行块移动压缩,回收磁盘空间 mvStore.compactMoveChunks(); // 获取当前存储填充率 double fillRate = mvStore.getCurrentFillRate(); // 其余MVStore原生方法均可在此直接调用
- 事务收尾
操作完成后记得处理手动开启的事务,避免事务泄露:
if (manualTx) { tx.commit(); }
注意事项
compactMoveChunks()是重IO操作,执行期间会占用大量磁盘、CPU资源,可能阻塞正常业务读写,禁止在业务高峰期频繁调用,建议在低峰期手动触发。- 上述调用依赖H2的内部非公开API,H2官方不保证跨版本兼容性,升级H2依赖后必须重新验证代码逻辑是否可用。
- 如果使用HikariCP、DBCP等连接池,必须保留循环解包连接的逻辑,直接强转连接会拿到代理对象,无法访问H2内部方法。
- 内存模式的H2实例虽然也能拿到MVStore,但实例随JVM进程销毁,压缩操作无实际收益。
内容的提问来源于stack exchange,提问作者Veselin
相关产品推荐
相关产品推荐

