为什么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个问题:
我使用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
答案 0 :(得分:35)
您正在检索的连接可能是一个包装连接。
如果确实需要获得底层Oracle连接,则应使用:
if (connection.isWrapperFor(OracleConnection.class)){
OracleConnection oracleConnection= connection.unwrap(OracleConnection.class);
}else{
// recover, not an oracle connection
}
自Java 1.6起,isWrapperFor
和unwrap
方法可用,并且应该由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();