I am using Apache Commons DBCP (commons-dbcp.jar
) Connection pool.
Once I obtained a connection from the pool it is wrapped in the
class org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper
.
My requirement is to pass an array of Strings to pl/sql stored procedure in Oracle.
Here is what I am doing in the following code snippet:
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();
On executing the above code, I get the following exception:
java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection at oracle.sql.ArrayDescriptor.createDescriptor
I tried to find out solution over this going throughout almost of the sites and forums, but couldn't get the satisfied answer or solution on the same.
By default, DBCP does not allow access to the "real" underlying database connection instance, so you cannot get to the Oracle class.
When configuring the pool, you can set
accessToUnderlyingConnectionAllowed = true
and then it works.
Default is false, it is a potential dangerous operation and misbehaving programs can do harmful things. (closing the underlying or continue using it when the guarded connection is already closed) Be careful and only use when you need direct access to driver specific extensions
NOTE: Do not close the underlying connection, only the original one.
If you are using a Java 6 compliant JDBC Connection, you can use code like the following:
OracleConnection oracleConnection = null;
try {
if (connection.isWrapperFor(OracleConnection.class)) {
oracleConnection = connection.unwrap(OracleConnection.class);
}
} catch (SQLException ex) {
// do something
}
return oracleConnection;
From this point on, use the oracleConnection
instead of the original connection
.
See http://docs.oracle.com/javase/6/docs/api/java/sql/Wrapper.html
Hmmm,I have meet the same solution like you.I think there a two position need you mention it. 1.Config Connection pool set accessToUnderlyingConnectionAllowed = "true" ; 2.The nightmare concerned to open source project. The terrable conceration. In this case,that is
org.apache.commons.dbcp.DelegatingConnection
is not equal to
org.apache.tomcat.dbcp.dbcp.DelegatingConnection
while in default apache common-dbcp.jar,you will never find the follow Class.But just the class is the key. So,we must find the Class in somewhere. I final find the package tomcat-dbcp.jar . You can get it from http://www.docjar.com/ After
import org.apache.tomcat.dbcp.dbcp.DelegatingConnection
,you can force cast you dbConn and get the Underlying Connection
oracle.jdbc.driver.OracleConnection delConn =
(oracle.jdbc.driver.OracleConnection)
((org.apache.tomcat.dbcp.dbcp.DelegatingConnection)c_stmt.getConnection()).getDelegate();
Then we can use delConn to get the ArrayDescriptor Remember one thing,in there,we do not need the
org.apache.commons.dbcp.DelegatingConnection Class
It's a so strange thing,but real work to the case.
Seen this post i can get the OracleConnection with this code:
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();
remember the commons-dbcp-1.4.jar neet to be in the class path
I'm positing this here to make sure anyone else looking for advice knows about the ultimate solution to this:
If you're forced to use the non bundled version of the persistence manager (because an old repository still uses that structure which is incompatible with the bundled layout), here what you can do, the solution is quite simple:
Download the sources for Jackrabbit Core (you can get them from the Jackrabbit website) Open the OraclePersistenceManager class and find the following line of code:
Object blob = createTemporary.invoke(null,
new Object[]{con, Boolean.FALSE, durationSessionConstant});
(Around line 377 - can also check the StackTrace for reference)
ConnectionFactory contains a static method that allows to unwrap a connection which is exactly what you need:
Object blob = createTemporary.invoke(null,
new Object[]{org.apache.jackrabbit.core.util.db.ConnectionFactory
.unwrap(con), Boolean.FALSE, durationSessionConstant});
You will need Maven 2+ in order to compile the sources, I did that and had no dependency problems, note that I compiled version 2.2.10 of Jackrabbit.
I also made sure to log a bug against Jackrabbit 2.2.11 (current release which still has the issue): https://issues.apache.org/jira/browse/JCR-3262
Hope this helps!
We use arrays in our calls to oracle stored procs and use oracle proprietary api to build arrays. This little check fixed the issue for us when using the functionality from stand alone apps using 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();
}
You will need commons-dbcp in the classpath/dependecies though.
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
<scope>provided</scope>
</dependency>
I had encountered the same issue. We were using spring and it has a class called NativeJdbcExtractor. It has many implementations and the following one works for TomCat. There are specific implementations for Websphere,Weblogic app servers.
<bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"></bean>
In your DAO you can inject the bean and use the following method
protected NativeJdbcExtractor jdbcExtractor;
Connection conn=jdbcExtractor.getNativeConnection(oracleConnection);
in your context definition add below tags to your existing xml definition.
factory="oracle.jdbc.pool.OracleDataSourceFactory
scope="Shareable"
type="oracle.jdbc.pool.OracleDataSource"
.
For anyone else looking, getDelegate()
and getInnermostDelegate()
both return NULL
in my code. However, from the debugger I found the OracleConnection as below. We use Spring JdbcTemplate throughout the application, which has the data source injected. We're on spring-jdbc-4.1.5.RELEASE.jar and ojdbc6.jar.
Connection conn = getJdbcTemplate().getDataSource().getConnection();
OracleConnection oracleConnection = ( OracleConnection ) conn.getMetaData().getConnection();
I am working with tomcat 8.5.8 and was facing this issue.
The below solution worked like charm.
The Code:
Delegating Connection delegate_conn = new Delegating Connection(connection)
conn = delegate_conn.getInnermostDelegate();
oracle.sql.ArrayDescriptor desc = oracle.sql.ArrayDescriptor.createDescriptor("TABLE_VIEW", conn);
The Solution:
Adding dependency for tomcat-dbcp 8.5.8
and add the same jar in lib folder of tomcat.
Seems tomcat has different jars for different versions starting from 7.0 (reference: https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp).
Hope it helps someone.
来源:https://stackoverflow.com/questions/6489514/apache-commons-dbcp-connection-object-problem-thread-classcastexception-in-org