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

时间:2013-03-18 17:42:49

标签: java oracle hibernate jdbc jndi

为什么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?

我使用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

10 个答案:

答案 0 :(得分:35)

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

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

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

自Java 1.6起,isWrapperForunwrap方法可用,并且应该由A / S连接包装器有意义地实现。

答案 1 :(得分:4)

连接池通常在真实连接实例周围有一个包装器,这就是你的转换失败的原因。

您正在做的事情无论如何都不会起作用,因为只有在建立连接时才会检查属性实例中的参数。由于您的连接已处于活动状态,因此不会更改任何内容。

您需要使用DBMS_APPLICATION_INFO.SET_CLIENT_INFO()来更改现有连接。

答案 2 :(得分:2)

这适用于那些通过搜索如何在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接线或连接池有关。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

您可以访问Wrapper中的内部OracleObject,在本例中为包装器 type是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;
 }

答案 5 :(得分:0)

尝试以下

我遇到了同样的问题。我们使用的是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);

答案 6 :(得分:0)

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

我正在使用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 configuration的某些内容实际上会导致解包失败。不知道为什么。

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

  

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

答案 7 :(得分:0)

经过反复试验。 这种方式有效:

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

但是这种方式为oraConnection返回了一个空指针:

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

答案 8 :(得分:-1)

以下是为了解决AQ的TopicConnection.getTopicSession =&gt; 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中使用它

答案 9 :(得分:-2)

尝试施放如下

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