Соединение не может быть передано в oracle.jdbc.OracleConnection

Почему java.sql.Connection не может быть передан в oracle.jdbc.OracleConnection в коде ниже?

Моя главная цель - перейти к новому имени пользователя для подключения к Oracle и сохранить его в таблице "SESSION", например, в столбце "osuser", потому что я хочу отслеживать в пользовательских изменениях БД и отображать их в таблице.

@Repository
public class AuditLogDAOImpl implements AuditLogDAO {

    @PersistenceContext(unitName="myUnitName")
    EntityManager em;

    @Resource(name = "dataSource")
    DataSource dataSource;

    public void init() {

        try {
            Connection connection = DataSourceUtils.getConnection(dataSource);
            OracleConnection oracleConnection = (OracleConnection) connection; //Here I got cast exception!

            String metrics[] = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
            metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = "my_new_username";

            oracleConnection.setEndToEndMetrics(metrics, (short) 0);

            java.util.Properties props = new java.util.Properties();
            props.put("osuser", "newValue");

            oracleConnection.setClientInfo(props);

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Вот журнал ошибок:

10:42:29,251 INFO  [STDOUT] [email protected]b
10:42:51,701 ERROR [STDERR] java.lang.ClassCastException: $Proxy286 cannot be cast to oracle.jdbc.OracleConnection

Как правило, у меня есть 2 проблемы в этом случае:

  • почему сбрасывается из Connection to OracleConnection и
  • Каков наилучший способ реализации моего намерения (я имею в виду установить новое имя пользователя для v $session.osuser в Oracle DB?

Я работаю с Oracle 11g, Hibernate (используя диспетчер сущностей), источником данных через jndi.

Пожалуйста, помогите, спасибо!

EDIT:

После некоторого улучшения проблема с кастингом все еще существует.

Улучшение:

Connection connection = DataSourceUtils.getConnection(dataSource);
connection = ((org.jboss.resource.adapter.jdbc.WrappedConnection)connection).getUnderlyingConnection();
OracleConnection oracleConnection = (OracleConnection) connection;

Ошибка:

java.lang.ClassCastException: $Proxy287 cannot be cast to org.jboss.resource.adapter.jdbc.WrappedConnection

Ответы

Ответ 1

Соединение, которое вы извлекаете, возможно, это завернутое соединение.

Если вам действительно нужно получить базовое соединение с Oracle, вы должны использовать:

if (connection.isWrapperFor(OracleConnection.class)){
   OracleConnection oracleConnection= connection.unwrap(OracleConnection.class);  
}else{
   // recover, not an oracle connection
}

Методы isWrapperFor и unwrap доступны начиная с Java 1.6 и должны быть осмысленно реализованы оболочками соединения A/S.

Ответ 2

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

То, что вы делаете, не будет работать, потому что параметры в экземпляре свойств проверяются только при установлении соединения. Поскольку у вас есть уже действующее соединение, это ничего не изменит.

Вам нужно использовать DBMS_APPLICATION_INFO.SET_CLIENT_INFO(), чтобы изменить это для существующего соединения.

Ответ 3

Это просто для людей, которые приходят сюда через поиск по настройке показателей в OracleConnection, я трачу много времени на это, поэтому может помочь кому-то.

После того, как вы получите свое "соединение", это должно работать:

DatabaseMetaData dmd = connection.getMetaData();
Connection metaDataConnection = null;

if(dmd != null)
{
    metaDataConnection = dmd.getConnection();
}

if(!(metaDataConnection instanceof OracleConnection))
{
    log.error("Connection is not instance of OracleConnection, returning");
    return; /* Not connection u want */
}

OracleConnection oraConnection = (OracleConnection)metaDataConnection;

String[] metrics = new String[END_TO_END_STATE_INDEX_MAX]; // Do the rest below...

Он работает для меня для OracleConnection, но я сталкиваюсь с проблемой diff при настройке показателей:

short zero = 0;
oraConnection.setEndToEndMetrics(metrics, zero);

После проксирования соединения через мой метод, когда я устанавливаю метрики несколько раз, я получаю:

java.sql.SQLRecoverableException: No more data to read from socket

Но я думаю, что это связано с некоторыми проводниками проводки Spring или пулом соединений.

Ответ 4

Я столкнулся с этой проблемой при использовании spring для подключения. Как правило, каждый слой добавляет обертку поверх базовых классов. Я только что сделал connection.getClass(). getName(), чтобы просмотреть тип среды выполнения перенастройки. Это будет Wrapper/proxy, над которым вы можете легко найти метод для получения базового типа OracleConnection.

Ответ 5

Вы можете получить доступ к внутреннему объекту OracleObject внутри Wrapper, в этом случае оболочка type - NewProxyConnection:

(Я использовал его в своем проекте, он работал... нет mistery, просто используйте отражение)

Field[] fieldsConn= connection.getClass().getDeclaredFields();

Object innerConnObject = getFieldByName(fieldsConn,"inner").get(connection);


if(innerConnObject instanceof OracleConnection ){
  OracleConnection oracleConn = (OracleConnection)innerConnObject;
 //OracleConnection unwrap = ((OracleConnection)innerConnObject).unwrap();
  // now you have the OracleObject that the Wrapper 
}


//Method: Set properties of the ooject accessible.
 public static  Field getFieldByName(Field[] campos, String name) {
    Field f = null;
    for (Field campo : campos) {
        campo.setAccessible(true);
        if (campo.getName().equals(name)) {
            f = campo;
            break;
        }
    }
    return f;
 }

Ответ 6

Попробуйте выполнить

Я столкнулся с той же проблемой. Мы использовали spring, и у него есть класс, называемый NativeJdbcExtractor. Он имеет множество реализаций, и для TomCat работает один из них. Для Jboss существует определенная реализация, называемая JBossNativeJdbcExtractor

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

В вашем DAO вы можете ввести bean и использовать следующий метод

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

Ответ 7

Не уверен, что моя ситуация связана, но с моим проектом просто изменение настройки конфигурации базы данных на самом деле приводит к отказу!

Я использую платформу Play с Scala; это работает для меня только тогда, когда logSql = false:

db.withConnection { implicit c  =>
  val oracleConnection = c.unwrap(classOf[OracleConnection])
}

(это только версия Scala для развертывания OracleConnection)

Когда я устанавливаю logSql = true, я получаю:

com.sun.proxy. $Proxy17 нельзя передать в oracle.jdbc.OracleConnection java.lang.ClassCastException: com.sun.proxy. $Proxy17 не может быть отброшен oracle.jdbc.OracleConnection

Итак, что-то об конфигурации logSql может привести к сбою разворота. Не знаю, почему.

С любой конфигурацией мой объект подключения:

HikariProxyConnection @1880261898 упаковка [email protected]

isWrapperFor(OracleConnection) истинно в обоих случаях

Это происходит с пулом соединений Hikari и Bone CP. Может быть, это ошибка в Oracle JDBC?

Версия драйвера JDBC Oracle в соответствии с MANIFEST.MF

Реализация-Версия: 11.2.0.3.0
Идентификатор репозитория: JAVAVM_11.2.0.4.0_LINUX.X64_130711

Ответ 8

После проб и ошибок. Этот способ работает:

        DelegatingConnection delConnection = new DelegatingConnection(dbcpConnection);
    oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();

Но этот путь вернул нулевой указатель для oraConnection:

DelegatingConnection delConnection = (DelegatingConnection) dbcpConnection;
    oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();

Ответ 9

Следующее работало, чтобы обойти AQ TopicConnection.getTopicSession = > JMS-112

//DEBUG: Native DataSource : weblogic.jdbc.common.internal.RmiDataSource
con = DataSource.getConnection();
debug("Generic SQL Connection: " + con.toString());               
//DEBUG: Generic Connection: weblogic.jdbc.wrapper.PoolConnection_oracle_jdbc_driver_T4CConnection
if (con != null && con.isWrapperFor(OracleConnection.class)) {
  WebLogicNativeJdbcExtractor wlne = new WebLogicNativeJdbcExtractor();//org.springframework to the rescue!!
  java.sql.Connection nativeCon = wlne.getNativeConnection(con);
  this.oraConnection = (OracleConnection) nativeCon;
  debug("Unwrapp SQL Connection: " + this.oraConnection.toString());
}

//DEBUG: Native Connection: oracle.jdbc.driver.T4CConnection è 

Теперь я мог бы использовать это в AQ- Factory без JMS-112

Ответ 10

попробуйте выполнить кастинг, как показано ниже

WrappedConnectionJDK6 wc = (WrappedConnectionJDK6) connection;
connection = wc.getUnderlyingConnection();