通过 JOOQ-meta 访问 H2 元模型时出现 SQLException

Posted

技术标签:

【中文标题】通过 JOOQ-meta 访问 H2 元模型时出现 SQLException【英文标题】:SQLException when accessing H2 metamodel through JOOQ-meta 【发布时间】:2016-03-03 22:42:11 【问题描述】:

我正在尝试使用 JOOQ 的 DSLContext.meta() 获取 H2 内存数据库中所有表的列表:

DSL_CONTEXT_PROVIDER.db().meta().getTables();

结果:

    java.lang.RuntimeException: org.jooq.exception.DataAccessException: Error while accessing DatabaseMetaData
        at MyTest.deleteEntities(MyTest.java:222)
        at MyTest.cleanupDatabase(MyTest.java:201)
        at MyTest.afterTestCase(MyTest.java:117)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        [... omitted for brevity ...]
    Caused by: org.jooq.exception.DataAccessException: Error while accessing DatabaseMetaData
        at org.jooq.impl.MetaImpl.getCatalogs(MetaImpl.java:160)
        at org.jooq.impl.MetaImpl.getSchemas(MetaImpl.java:168)
        at org.jooq.impl.MetaImpl.getTables(MetaImpl.java:179)
        at MyTest.deleteEntities(MyTest.java:210)
        ... 29 more
    Caused by: org.h2.jdbc.JdbcSQLException: The object is already closed [90007-174]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:332)
        at org.h2.message.DbException.get(DbException.java:172)
        at org.h2.message.DbException.get(DbException.java:149)
        at org.h2.message.DbException.get(DbException.java:138)
        at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1410)
        at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1388)
        at org.h2.jdbc.JdbcDatabaseMetaData.checkClosed(JdbcDatabaseMetaData.java:2963)
        at org.h2.jdbc.JdbcDatabaseMetaData.getCatalogs(JdbcDatabaseMetaData.java:756)
        at org.jooq.impl.MetaImpl.getCatalogs(MetaImpl.java:143)
        ... 32 more

DSL_CONTEXT_PROVIDER.db() 看起来像这样:

JdbcDataSource h2ds = new JdbcDataSource();
h2ds.setURL("jdbc:h2:mem:testDB;create=true");
h2ds.setUser("");
h2ds.setPassword("");
return DSL.using(new DefaultConfiguration().set(new DataSourceConnectionProvider(h2ds)));

普通查询适用于上述配置,但不适用于meta().getTables()。如果我将DataSourceConnectionProvider 替换为不关闭连接的匿名实现,则不会再引发异常。

似乎H2不赞成在底层连接关闭后对connection.getMetaData()返回的对象调用getCatalogs()之类的方法。这是jooq-meta 中的错误(我使用3.7.0)还是我的配置有缺陷?

【问题讨论】:

【参考方案1】:

jOOQ 3.7.0 / 3.7.1 及更早版本将DatabaseMetaData 缓存在org.jooq.Meta 中。这是一个错误 (4762),很快就会修复。

您遇到此问题的原因是因为您使用的是DataSourceConnectionProvider,它并不是真正适用于独立连接或“简单”DataSources。它在每次查询后关闭连接(通常转换为将其返回到池中)。关闭连接后,缓存的DatabaseMetaData 引用已过时。

您已经记录了解决方法:不要将“简单”DataSource 与 jOOQ 的 DSLContext.meta() API 一起使用。

【讨论】:

以上是关于通过 JOOQ-meta 访问 H2 元模型时出现 SQLException的主要内容,如果未能解决你的问题,请参考以下文章

使用 Java 和元模型时出现异常 java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo cannot

尝试使用 H2 数据库更新 JDBC ResultSet 时出现异常

无法连接到元数据库 h2 数据库

创建 SageMaker 模型时出现 ValidationError

尝试从 Oracle 导入到 H2 时出现 Temenos DBImport 错误

在 h2 数据库上运行选择查询时出现问题