17

以下のコードで java.sql.Connection を oracle.jdbc.OracleConnection にキャストできないのはなぜですか?

私の主な目標は、Oracle接続に新しいユーザー名を渡し、DBユーザーの変更を追跡してテーブルに表示したいので、たとえば「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
4

10 に答える 10

40

取得している接続は、おそらくラップされた接続です。

基盤となるOracle接続を本当に取得する必要がある場合は、次を使用する必要があります。

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

およびメソッドはJava1.6以降で使用可能であり、A/S接続ラッパーによって意味のある形で実装される必要がありますisWrapperForunwrap

于 2013-03-18T17:55:55.687 に答える
4

接続プールには通常、実際の接続インスタンスの周りにラッパーがあるため、キャストが失敗します。

プロパティ インスタンスのパラメータは接続が確立されたときにのみチェックされるため、あなたがしていることはとにかくうまくいきません。すでにアクティブな接続があるため、何も変更されません。

DBMS_APPLICATION_INFO.SET_CLIENT_INFO()既存の接続に対してこれを変更するには、使用する必要があります。

于 2013-03-18T17:46:41.177 に答える
3

これは、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ワイヤリング初期化または接続プールに関係していると思います.

于 2014-02-28T23:56:02.913 に答える
1

Wrapper 内の内部 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;
 }
于 2014-09-26T07:44:34.140 に答える
1

スプリングを使用して接続を取得するときに、この問題に直面していました。通常、各レイヤーは基本クラスにラッパーを追加します。私はちょうどconnection.getClass().getName()を実行して、返される接続のランタイムタイプを確認しました。これは、ベースの OracleConnection タイプを取得するメソッドを簡単に見つけることができるラッパー/プロキシになります。

于 2013-03-18T17:49:38.367 に答える
0

以下を試してください

私は同じ問題に遭遇しました。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);
于 2013-10-16T04:24:30.730 に答える
0

試行錯誤の末。この方法は機能します:

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

しかし、この方法では oraConnection に対して null ポインタが返されました。

DelegatingConnection delConnection = (DelegatingConnection) dbcpConnection;
    oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();
于 2019-05-03T07:34:26.547 に答える
-1

以下は、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 è 

これで、AQ-Factory w/o JMS-112 でこれを使用できるようになりました

于 2016-02-19T05:50:33.877 に答える