Проблема с объектом подключения Apache Commons DBCP, поток: ClassCastException в org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper

Я использую пул соединений Apache Commons DBCP (commons-dbcp.jar).

Как только я получил соединение из пула, оно завернуто в класс org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.

Мое требование - передать массив строк хранимой процедуре pl/sql в Oracle.

Вот что я делаю в следующем фрагменте кода:

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

Я пытался найти решение по этому поводу почти на всех сайтах и ​​форумах, но не смог получить удовлетворительного ответа или решения по этому поводу.


person Prodigy    schedule 27.06.2011    source источник
comment
Почему вы заворачиваете dbConn только для того, чтобы развернуть его снова? Что произойдет, если вы вызовете getInnermostDelegate непосредственно на dbConn?   -  person Thilo    schedule 27.06.2011


Ответы (11)


По умолчанию DBCP не разрешает доступ к «реальному» базовому экземпляру подключения к базе данных, поэтому вы не можете получить доступ к классу Oracle.

При настройке пула вы можете установить

accessToUnderlyingConnectionAllowed = true

и тогда это работает.

Значение по умолчанию — false, это потенциально опасная операция, а некорректно работающие программы могут причинить вред. (закрытие базового или продолжение его использования, когда защищенное соединение уже закрыто) Будьте осторожны и используйте только тогда, когда вам нужен прямой доступ к расширениям, специфичным для драйвера.

ПРИМЕЧАНИЕ. Не закрывайте базовое соединение, только исходное.

person Thilo    schedule 27.06.2011
comment
У меня есть следующие параметры, используемые в деталях ресурса, но они все еще не работают. InitialSize=5 maxActive=5 minidle= 5 maxIdle=5 maxWait=20000 removeAbandoned=true removeAbandonedTimeout=60 maxIdleTime=3000 accessToUnderlyingConnectionAllowed=true - person Prodigy; 27.06.2011
comment
@Prodigy У тебя есть решение? я столкнулся с той же проблемой. - person Shibankar; 12.08.2015
comment
Просто отметить. Это решение работает только в сочетании с ответом ниже: stackoverflow.com/a/14327357/912829 - person ACV; 19.09.2017

Если вы используете соединение JDBC, совместимое с Java 6, вы можете использовать следующий код:

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

person Jeff Olson    schedule 14.01.2013
comment
Здесь ничего не стоит то, что вы хотите импортировать interface OracleConnection в oracle.jdbc, а не конкретную реализацию с тем же именем. - person Andrew; 22.04.2016

Увидев этот пост, я могу получить 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 не должен быть в пути к классу

person Leonardo Eloy    schedule 20.04.2012

Хм, у меня такое же решение, как и у вас. Я думаю, что вам нужно упомянуть о двух позициях. 1.Настройка пула соединений: accessToUnderlyingConnectionAllowed = "true" ; 2. Кошмар связан с проектом с открытым исходным кодом. Ужасное сосредоточение. В данном случае это

org.apache.commons.dbcp.DelegatingConnection 

не равно

org.apache.tomcat.dbcp.dbcp.DelegatingConnection

в то время как в apache по умолчанию common-dbcp.jar вы никогда не найдете следующий класс. Но ключом является только класс. Итак, мы должны где-то найти Класс. Наконец я нашел пакет 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

Это такая странная вещь, но реальная работа по делу.

person Rui Zha    schedule 06.04.2012
comment
омг, это ответ, который мне нужен, очень сбивает с толку, что кот изменил пути... - person Reimius; 28.08.2013

Я размещаю это здесь, чтобы убедиться, что любой, кто ищет совета, знает об окончательном решении этой проблемы:

Если вы вынуждены использовать несвязанную версию менеджера постоянства (поскольку старый репозиторий все еще использует эту структуру, которая несовместима со связанной структурой), вот что вы можете сделать, решение довольно простое:

Загрузите исходные коды для ядра Jackrabbit (вы можете получить их с веб-сайта 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+ для компиляции исходников, я сделал это и не имел проблем с зависимостями, обратите внимание, что я скомпилировал версию 2.2.10 Jackrabbit.

Я также записал ошибку в Jackrabbit 2.2.11 (текущий выпуск, в котором все еще есть проблема): https://issues.apache.org/jira/browse/JCR-3262

Надеюсь это поможет!

person Harald Scheckenbacher    schedule 16.03.2012

Мы используем массивы в наших вызовах хранимых процессов оракула и используем проприетарный 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();
    }

Однако вам понадобится commons-dbcp в пути к классам/зависимостях.

    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
        <scope>provided</scope>
    </dependency>
person chinto    schedule 25.05.2012

Я столкнулся с той же проблемой. Мы использовали 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);
person Sherin Syriac    schedule 16.10.2013
comment
Это единственный ответ, который сработал для меня. accessToUnderlyingConnectionAllowed ничего не изменил, а другие ответы добавляют явные зависимости к commons-dbcp, что неприемлемо. Спасибо! - person Xavi López; 04.04.2016

в вашем определении контекста добавьте теги ниже к существующему определению xml.

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

.

person ibrahimbayer    schedule 30.07.2015

Для всех, кто ищет, 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();
person Severus Snape    schedule 19.02.2016

Я работаю с tomcat 8.5.8 и столкнулся с этой проблемой.
Приведенное ниже решение сработало как шарм.


Код:

Delegating Connection delegate_conn = new Delegating Connection(connection)
conn = delegate_conn.getInnermostDelegate();
oracle.sql.ArrayDescriptor desc = oracle.sql.ArrayDescriptor.createDescriptor("TABLE_VIEW", conn);

Решение:

Добавление зависимости для tomcat-dbcp 8.5.8 и добавление того же jar в папку lib tomcat.
Похоже, у tomcat есть разные jar для разных версий, начиная с 7.0 (ссылка: https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp).

Надеюсь, это поможет кому-то.

person ashutosh singh    schedule 19.12.2016

Я использую java7 и ojdbc7.jar и Tomcat 8.

У меня была такая же проблема в tomcat при преобразовании ((OracleConnection)connection).createARRAY

После поиска множества решений и форумов, наконец, сработало решение для меня,

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), вы получите false. вам нужно использовать cs.getConnection.

Может поможет кому.

person Mohan    schedule 06.11.2019