以下のコードでJava.sql.ConnectionをOracle.jdbc.OracleConnectionにキャストできないのはなぜですか?
私の主な目標は、DB接続の変更を追跡してテーブルに表示するため、新しいユーザー名を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
取得する接続は、おそらくラップ接続です。
本当に基礎となる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の配線初期化または接続プールに関係していると思います。
スプリングを使用して接続するときにこの問題に直面していました。通常、各レイヤーは基本クラスにラッパーを追加します。 connection.getClass()。getName()を実行して、再調整中の接続のランタイムタイプを確認しました。これは、ベースOracleConnectionタイプを取得するメソッドを簡単に見つけることができるラッパー/プロキシになります。
ラッパー内の内部OracleObjectにアクセスできます。この場合、ラッパータイプは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にNULLポインターが返されました。
DelegatingConnection delConnection = (DelegatingConnection) dbcpConnection;
oraConnection = (Oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();
以下を試してください
同じ問題に遭遇しました。 Springを使用しており、NativeJdbcExtractorというクラスがあります。多くの実装があり、Tomcatには次の実装が機能します。 JBossNativeJdbcExtractorと呼ばれるJbossの特定の実装があります
<bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"></bean>
DAOで、Beanを注入し、次の方法を使用できます
protected NativeJdbcExtractor jdbcExtractor;
Connection conn=jdbcExtractor.getNativeConnection(oracleConnection);