Apache Commons DBCP连接对象问题,org.apache.tomcat.dbcp.dbcp.PoolingDataSource中的Thread:ClassCastException $ PoolGuardConnectionWrapper

时间:2011-06-27 06:54:00

标签: java jdbc apache-commons-dbcp

我正在使用Apache Commons DBCP(commons-dbcp.jar)连接池。

一旦我从游泳池获得连接,它就被包裹在游戏中 班org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper

我的要求是将一个字符串数组传递给Oracle中的pl / sql存储过程。

以下是我在以下代码段中所做的事情:

Connection dbConn = ConnectionManager.ds.getConnection();
//The above statement returns me an connection wrapped in the class
//org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.

org.apache.commons.dbcp.DelegatingConnection del = new org.apache.commons.dbcp.DelegatingConnection(dbConn.getConnection());
con = del.getInnermostDelegate();

cs = con.prepareCall("call SP_NAME(?,?,?,?)");
oracle.sql.ArrayDescriptor arDesc= oracle.sql.ArrayDescriptor.createDescriptor("ARRAY_NAME", (OracleConnection) con);

CallableStatement c_stmt = conn.prepareCall("begin update_message_ids_ota
(:x); end;" );
c_stmt.setArray( 1, array_to_pass );
c_stmt.execute();

执行上面的代码时,我得到以下异常:

  

java.lang.ClassCastException:org.apache.commons.dbcp.PoolingDataSource $ PoolGuardConnectionWrapper无法强制转换为oracle.jdbc.OracleConnection       在oracle.sql.ArrayDescriptor.createDescriptor

我试图在几乎所有的网站和论坛中找到解决方案,但无法得到满意的答案或解决方案。

11 个答案:

答案 0 :(得分:23)

默认情况下,DBCP不允许访问“真正的”底层数据库连接实例,因此无法访问Oracle类。

configuring游泳池时,您可以设置

accessToUnderlyingConnectionAllowed = true

然后它有效。

  

默认为假,这是一个潜在的危险操作,行为不端的程序可以做有害的事情。 (当保护连接已经关闭时关闭底层或继续使用它)小心并且仅在需要直接访问特定于驱动程序的扩展时使用

     

注意:请勿关闭基础连接,只关闭原始连接。

答案 1 :(得分:16)

如果您使用的是Java 6兼容的JDBC连接,则可以使用以下代码:

OracleConnection oracleConnection = null;
try {
    if (connection.isWrapperFor(OracleConnection.class)) {
        oracleConnection = connection.unwrap(OracleConnection.class);
    }
} catch (SQLException ex) {
    // do something
}
return oracleConnection;

从现在开始,使用oracleConnection代替原始connection

请参阅http://docs.oracle.com/javase/6/docs/api/java/sql/Wrapper.html

答案 2 :(得分:5)

看到这篇文章,我可以使用以下代码获取OracleConnection:

DataSource ds1 = // get the org.apache.commons.dbcp.PoolingDataSource
org.apache.tomcat.dbcp.dbcp.DelegatingConnection del = new org.apache.tomcat.dbcp.dbcp.DelegatingConnection(cds1.getConnection());
OracleConnection con = (OracleConnection) del.getInnermostDelegate();

记住commons-dbcp-1.4.jar需要在类路径中

答案 3 :(得分:4)

嗯,我遇到了和你一样的解决方案。我认为有两个位置需要你提一下。 1.Config连接池设置accessToUnderlyingConnectionAllowed =“true”; 2.关于开源项目的噩梦。可怕的概念。在这种情况下,那 是

org.apache.commons.dbcp.DelegatingConnection 

不等于

org.apache.tomcat.dbcp.dbcp.DelegatingConnection

在默认的apache common-dbcp.jar中,你永远不会找到跟随Class.But只是类是关键。所以,我们必须在某个地方找到Class。我最终找到了包 tomcat-dbcp .jar。你可以从http://www.docjar.com/获得它 之后

import org.apache.tomcat.dbcp.dbcp.DelegatingConnection

,你可以强迫你施放dbConn并获得底层连接

oracle.jdbc.driver.OracleConnection delConn = 

(oracle.jdbc.driver.OracleConnection) 

((org.apache.tomcat.dbcp.dbcp.DelegatingConnection)c_stmt.getConnection()).getDelegate();

然后我们可以使用delConn来获取ArrayDescriptor 记住一件事,在那里,我们不需要

org.apache.commons.dbcp.DelegatingConnection Class

这是一件非常奇怪的事情,但对案件的真实工作。

答案 4 :(得分:2)

我在这里提出这个问题,以确保其他寻求建议的人都知道最终的解决方案:

如果您被迫使用非捆绑版本的持久性管理器(因为旧的存储库仍然使用与捆绑布局不兼容的结构),在这里您可以做的,解决方案非常简单:

下载Jackrabbit Core的来源(您可以从Jackrabbit网站获取) 打开OraclePersistenceManager类并找到以下代码行:

Object blob = createTemporary.invoke(null,
                new Object[]{con, Boolean.FALSE, durationSessionConstant});

(第377行 - 也可以查看StackTrace以供参考)

ConnectionFactory包含一个静态方法,允许解开正是您所需的连接:

Object blob = createTemporary.invoke(null,
                new Object[]{org.apache.jackrabbit.core.util.db.ConnectionFactory
                        .unwrap(con), Boolean.FALSE, durationSessionConstant});

你需要Maven 2+才能编译源码,我这样做并且没有依赖性问题,请注意我编译了Jackrabbit版本2.2.10。

我还确保记录针对Jackrabbit 2.2.11的错误(当前版本仍有问题): https://issues.apache.org/jira/browse/JCR-3262

希望这有帮助!

答案 5 :(得分:1)

我们在调用oracle存储过程中使用数组,并使用oracle专有api构建数组。当使用commons-dbcp的独立应用程序中的功能时,这个小小的检查为我们解决了问题。

    if (conn instanceof org.apache.commons.dbcp.DelegatingConnection)
    {
        log.debug("detected apache commons dbcp datasource");
        conn = ((org.apache.commons.dbcp.DelegatingConnection) conn).getInnermostDelegate();
    }

你需要在classpath / dependecies中使用commons-dbcp。

    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
        <scope>provided</scope>
    </dependency>

答案 6 :(得分:1)

我遇到了同样的问题。我们使用的是spring,它有一个叫做的类 NativeJdbcExtractor。它有许多实现,下面的一个适用于TomCat。 Websphere,Weblogic应用服务器有特定的实现。

<bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"></bean>

在DAO中,您可以注入bean并使用以下方法

protected NativeJdbcExtractor jdbcExtractor;
Connection conn=jdbcExtractor.getNativeConnection(oracleConnection);

答案 7 :(得分:0)

在您的上下文定义中,将以下标记添加到现有的xml定义中。

factory="oracle.jdbc.pool.OracleDataSourceFactory
scope="Shareable"
type="oracle.jdbc.pool.OracleDataSource"

答案 8 :(得分:0)

对于其他人来说,getDelegate()getInnermostDelegate()都会在我的代码中返回NULL。但是,从调试器中我发现了OracleConnection,如下所示。我们在整个应用程序中使用Spring JdbcTemplate,它注入了数据源。我们在spring-jdbc-4.1.5.RELEASE.jar和ojdbc6.jar上。

Connection conn = getJdbcTemplate().getDataSource().getConnection();

OracleConnection oracleConnection = ( OracleConnection ) conn.getMetaData().getConnection();

答案 9 :(得分:0)

我正在使用tomcat 8.5.8并且正面临这个问题 以下解决方案就像魅力一样。

守则:

T1  Person 173 183  Alexanders
T2  Person 444 450  Hannah
T3  Person 754 766  Corneliszoon
T4  GPE 787 796 Antwerpen
T5  Person 824 833  Alexander

解决方案:

Delegating Connection delegate_conn = new Delegating Connection(connection) conn = delegate_conn.getInnermostDelegate(); oracle.sql.ArrayDescriptor desc = oracle.sql.ArrayDescriptor.createDescriptor("TABLE_VIEW", conn); 添加依赖项 并在tomcat的lib文件夹中添加相同的jar 似乎tomcat对于从7.0开始的不同版本有不同的jar(参考:https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp)。

希望它有所帮助。

答案 10 :(得分:0)

我正在使用java7&ojdbc7.jar和Tomcat8。

在转换((OracleConnection)connection).createARRAY

时,tomcat存在相同的问题

在搜索了很多解决方案和论坛之后,最后对我来说可行的解决方案是

Connection connection = datasource.getConnection();
CallableStatement cs = connection.prepareCall("{ CALL PKG.PROCEDURE(?)}");

if(cs.getConnection().isWrapperFor(OracleConnection.class)) {
  OracleConnection orConn = cs.getConnection().unwrap(OracleConnection.class);
  orConn.createARRAY ..// is working perfectly.

}

如果您执行了 connection.isWrapperFor(OracleConnection.class),您将得到假。您需要使用cs.getConnection。

可能会帮助某人。