当与 Jetty 上下文配置加载的 DBCP 和 JNDI 一起使用时,PostgreSQL JDBC 驱动程序无法推断 SQL 类型

PostgreSQL JDBC driver can't infer the SQL type when used with DBCP and JNDI loaded by Jetty context configuration

我遇到了一个非常混乱的情况,我不确定这是否是一个错误。

我正在尝试将 PostgreSQL 用作由 Jetty 管理的池化数据源。 DBCP2.1 也用作池管理器。数据源在类似于此的 Jetty 上下文配置文件中配置:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">

<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">

    <Set name="contextPath">/</Set>
    <Set name="war">
        <Property name="jetty.webapps" default="."/>/root.war
    </Set>
    <Set name="extractWAR">true</Set>
    <Set name="copyWebDir">false</Set>
    <Set name="configurationDiscovered">true</Set>


    <!-- Postgresql connection pool using DBCP2 -->
    <New id="ketabakds" class="org.eclipse.jetty.plus.jndi.Resource">
        <Arg>
            <Ref refid='wac'/>
        </Arg>
        <Arg>jdbc/dbpool</Arg>
        <Arg>
            <New class="org.apache.commons.dbcp2.BasicDataSource">
                <Set name="driverClassName">org.postgresql.Driver</Set>
                <Set name="url">jdbc:postgresql://localhost:5432/pg_databse</Set>
                <Set name="username">pg_user</Set>
                <Set name="password">pg_pass</Set>
            </New>
        </Arg>
    </New>

</Configure>

稍后在我的代码中使用如下内容检索数据源:

        DataSource source = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/dbpool");

这一切工作正常,直到我尝试使用 PGobject class 在准备好的语句上设置任何内容。例如,我有这段代码可以传递一些 JSON:

        PGobject jsonObject = new PGobject();
        jsonObject.setType(JSON_TYPE);
        jsonObject.setValue(json);

        statement = aConnection.prepareStatement(
                "insert into " +
                        tableName() +
                        " (data) values (?)"
        );

        statement.setObject(1, jsonObject);
        statement.executeUpdate();

这里我得到这个错误:

org.postgresql.util.PSQLException: Can't infer the SQL type to use for an instance of org.postgresql.util.PGobject. Use setObject() with an explicit Types value to specify the type to use.
    at org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1039) ~[postgresql-9.4.1208.jar:9.4.1208]
    at org.apache.commons.dbcp2.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:189) ~[commons-dbcp2-2.1.1.jar:2.1.1]
    at org.apache.commons.dbcp2.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:189) ~[commons-dbcp2-2.1.1.jar:2.1.1]

我什至调试到 PgPreparedStatement.java:1039,非常有趣的一点是传递的值(名为 x)仍然是 PGobject 类型,但评估 PGobject 的 x 实例 returns 为 false。

我怀疑问题是 Jetty 加载了 PG 的 JDBC 驱动程序两次。一次是在加载上下文配置时,第二次是在 WAR 应用程序本身加载时。因此有两个 PGobject classes,即使它们都有确切的包名称。

我不是码头专业人士,但这可能吗?是否有解决方案,以便我可以使用 PGobject 将值传递给准备好的语句?

好的,我找到问题的原因了。我怀疑 PostgreSQL JDBC 驱动程序被 Jetty 加载了两次,一次是上下文配置的结果,第二次是在 Web 应用程序中。

我通过从 Web 应用程序中删除依赖项并将其留给码头来加载应用程序来解决问题。由于我的构建工具是 Gradle,这意味着我将 web 应用程序的 postgresql 驱动程序的依赖项设置为 compileOnly。