Невозможно привести соединение к 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] org.jboss.resource.adapter.jdbc.jdk6.WrappedConnectionJDK6@bcc8cb
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?

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

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

РЕДАКТИРОВАТЬ:

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

Улучшение:

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

9 ответов

Соединение, которое вы получаете, вероятно, является подключенным.

Если вам действительно нужно получить базовое соединение с 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.

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

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

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

Это просто для людей, которые приходят сюда с помощью поиска о том, как установить метрики в 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 или пулом соединений.

Попробуйте следующее

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

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

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

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

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

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

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

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;
 }

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

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

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

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

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

Я использую платформу 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 упаковка oracle.jdbc.driver.T4CConnection@6b28f065

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

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

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

Версия-реализация: 11.2.0.3.0
Код хранилища: JAVAVM_11.2.0.4.0_LINUX.X64_130711

Следующее работало, чтобы обойти TopicConnection.getTopicSession AQ => 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

Попробуйте кастинг как ниже

WrappedConnectionJDK6 wc = (WrappedConnectionJDK6) connection;
connection = wc.getUnderlyingConnection();
Другие вопросы по тегам