Невозможно привести соединение к 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();