无法将连接强制转换为oracle.jdbc.OracleConnection

为什么java.sql.Connection无法在下面的代码中强制转换为oracle.jdbc.OracleConnection?

我的主要目标是传递给Oracle连接新用户名并将其保存在例如’osuser’列的’SESSION’表中,因为我想跟踪数据库用户更改并在表中显示它。

@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到OracleConnection的转换失败了
  • 实现我的意图的最佳方法是什么(我的意思是在Oracle DB中将新用户名设置为v $ session.osuser?

我通过jndi使用Oracle 11g,Hibernate(使用实体管理器),数据源。

请帮忙,谢谢!

编辑:

经过一些改进后,铸造问题仍然存在。

改进:

 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 

您正在检索的连接可能是一个包装连接。

如果您确实需要获得底层Oracle连接,则应使用:

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

isWrapperForisWrapperFor方法自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,但在设置指标时我遇到了差异问题:

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

通过我的方法代理连接后,我设置了几次指标,我得到:

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

但我认为它与一些Spring接线或连接池有关。

当我使用spring来获取连接时,我遇到了这个问题。 通常,每个层都在基本类上添加一个包装器。 我刚刚完成了connection.getClass()。getName()来查看正在重新调整的连接的运行时类型。 它将是一个包装器/代理,您可以通过它轻松找到获取基本OracleConnection类型的方法。

您可以访问Wrapper中的内部OracleObject,在这种情况下,包装类型是NewProxyConnection:

(我在我的项目中使用它,它工作……没有谜,只是使用reflection)

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

请尝试以下方法

我遇到过同样的问题。 我们使用spring,它有一个名为NativeJdbcExtractor的类。 它有许多实现,以下一个适用于TomCat。 Jboss有一个特定的实现叫做JBossNativeJdbcExtractor

  

在DAO中,您可以注入bean并使用以下方法

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

不确定我的情况是否相关,但是对于我的项目,只需更改数据库配置设置实际上会导致解包失败!

我正在使用Scala的Play框架; 这只适用于logSql = false时

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

(这只是解开OracleConnection的Scala版本)

当我设置logSql = true时 ,我得到:

com.sun.proxy。$ Proxy17无法强制转换为oracle.jdbc.OracleConnection java.lang.ClassCastException:com.sun.proxy。$ Proxy17无法强制转换为oracle.jdbc.OracleConnection

所以关于logSql配置的一些事实上可能导致unwrap失败。 不知道为什么。

无论使用哪种配置,我的连接对象都是:

HikariProxyConnection @ 1880261898包装oracle.jdbc.driver.T4CConnection@6b28f065

isWrapperFor(OracleConnection)在两种情况下都是正确的

这种情况发生在Hikari Connection Pool和Bone CP上。 也许这是Oracle JDBC中的一个错误?

根据MANIFEST.MF的 Oracle JDBC驱动程序版本

实现版本:11.2.0.3.0
存储库ID:JAVAVM_11.2.0.4.0_LINUX.X64_130711

以下是解决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 è 

现在我可以在没有JMS-112的AQ-Factory中使用它

尝试如下铸造

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