web-dev-qa-db-fra.com

La connexion ne peut pas être convertie en Oracle.jdbc.OracleConnection

Pourquoi Java.sql.Connection ne peut pas être converti en Oracle.jdbc.OracleConnection dans le code ci-dessous?

Mon objectif principal est de transmettre à la connexion Oracle un nouveau nom d'utilisateur et de l'enregistrer dans le tableau "SESSION", par exemple dans la colonne "osuser", car je souhaite suivre les modifications apportées aux utilisateurs de la base de données et les afficher dans le tableau.

@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();
        }
    }
}

Voici le journal des erreurs:

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

Généralement j'ai 2 problème dans ce cas:

  • pourquoi la conversion de Connection vers OracleConnection échoue et
  • quel est le meilleur moyen d'implémenter mon intention (je veux dire, définissez le nouveau nom d'utilisateur sur v $ session.osuser dans Oracle DB?

Je travaille avec Oracle 11g, Hibernate (à l'aide du gestionnaire d'entités), source de données via jndi.

S'il vous plaît aider, merci!

MODIFIER:

Après quelques améliorations, le problème du casting existe toujours.

Amélioration:

Connection connection = DataSourceUtils.getConnection(dataSource);
connection = ((org.jboss.resource.adapter.jdbc.WrappedConnection)connection).getUnderlyingConnection();
OracleConnection oracleConnection = (OracleConnection) connection;

Erreur:

Java.lang.ClassCastException: $Proxy287 cannot be cast to org.jboss.resource.adapter.jdbc.WrappedConnection
15
Roman

La connexion que vous récupérez est probablement une connexion encapsulée.

Si vous vraiment devez obtenir la connexion Oracle sous-jacente, vous devez utiliser:

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

Les méthodes isWrapperFor et unwrap sont disponibles depuis Java 1.6 et doivent être implémentées de manière significative par les wrappers de connexion A/S.

34
Carlo Pellegrini

Le pool de connexions a généralement un wrapper autour de l'instance de connexion réelle, c'est pourquoi votre conversion échoue. 

De toute façon, ce que vous faites ne fonctionnerait pas, car les paramètres de l’instance de propriétés ne sont vérifiés que lorsque la connexion est établie. Comme vous avez une connexion déjà active, cela ne changera rien. 

Vous devez utiliser DBMS_APPLICATION_INFO.SET_CLIENT_INFO() pour pouvoir le changer pour une connexion existante.

3

Ceci concerne uniquement les personnes qui viennent ici via une recherche sur la manière de définir des métriques dans OracleConnection. Je passe beaucoup de temps là-dessus, donc je pourrais aider quelqu'un.

Après avoir obtenu votre "connexion", cela devrait fonctionner:

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...

Cela fonctionne pour moi pour OracleConnection, mais je suis confronté à un problème de différenciation lors de la définition de métriques:

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

Après un proxy de connexion via ma méthode où je définis plusieurs métriques, je reçois:

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

Mais je pense que cela a à voir avec certaines entrées de câblage Spring ou un pool de connexion.

2
Jenya G

j'avais fait face à ce problème en utilisant Spring pour obtenir des connexions. En général, chaque couche ajoute un wrapper aux classes de base. Je venais de faire connection.getClass (). getName () pour voir le type d'exécution de la connexion en cours de réaccord. Ce sera un Wrapper/proxy sur lequel vous pourrez facilement trouver la méthode pour obtenir le type de base OracleConnection. 

1
Akhilesh Singh

Vous pouvez accéder à OracleObject interne dans un wrapper, dans ce cas, le wrapper Type est NewProxyConnection:

(Je l'ai utilisé dans mon projet, cela a fonctionné ... pas de mystère, utilisez simplement la réflexion)

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

Je ne suis pas sûr que ma situation soit liée, mais avec mon projet, le simple changement d'un paramètre de configuration de base de données entraîne l'échec de l'extraction!

J'utilise le framework Play avec Scala; cela fonctionne pour moi uniquement lorsque logSql = false:

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

(il ne s'agit que de la version Scala du déploiement d'une connexion OracleConnection)}

Lorsque je règle logSql = true, je reçois:

com.Sun.proxy. $ Proxy17 ne peut pas être converti en Oracle.jdbc.OracleConnection Java.lang.ClassCastException: com.Sun.proxy. $ Proxy17 ne peut pas être converti en Oracle.jdbc.OracleConnection

Donc, quelque chose à propos de la configuration de logSql peut réellement causer l’échec de la décompression. Aucune idée pourquoi.

Quelle que soit la configuration, mon objet de connexion est:

HikariProxyConnection @ 1880261898 envelopper Oracle.jdbc.driver.T4CConnection@6b28f065

isWrapperFor(OracleConnection) est vrai dans les deux cas

Cela se produit avec Hikari Connection Pool et Bone CP. Peut-être que c'est un bogue dans Oracle JDBC?

Version du pilote JDBC Oracle selon MANIFEST.MF

Version d'implémentation: 11.2.0.3.0
Identifiant du référentiel: JAVAVM_11.2.0.4.0_LINUX.X64_130711

0
Arlo

Essayez ce qui suit

J'avais rencontré le même problème. Nous utilisions spring et il existe une classe appelée NativeJdbcExtractor. Il a de nombreuses implémentations et la suivante fonctionne pour Tomcat. Il existe une implémentation spécifique pour Jboss appelée JBossNativeJdbcExtractor.

<bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"></bean>

Dans votre DAO, vous pouvez injecter le haricot et utiliser la méthode suivante

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