2010-11-11 11 views
6

Estoy tratando de utilizar el "New Methods for National Character Set Type Data in JDK 1.6", para obtener una solución estándar JDBCpara manejar caracteres cirílicos, pero cuando llega a la ejecución de cualquier línea con el tipo NVARCHAR, por ejemplo, :Types.NVARCHAR con controlador JDBC de Oracle para trabajar con caracteres cirílicos

preparedSelect.setObject(3, "суббота", Types.NVARCHAR); 

entonces consigo esta excepción:

java.sql.SQLException: Invalid column type 
    at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70) 
    at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:131) 
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:197) 
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:261) 
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:269) 
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:490) 
    at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:7922) 
    at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:7502) 
    at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:7975) 
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:222) 

también probé a usar setNString() pero me da una excepción aún más extraño:

java.lang.AbstractMethodError: oracle.jdbc.driver.OraclePreparedStatementWrapper.setNString(ILjava/lang/String;)V 

Si uso java -Doracle.jdbc.defaultNChar = true myApplication con Types.VARCHAR normal, las palabras rusas se almacenan correctamente. Pero el uso de -Doracle.jdbc.defaultNChar = true no es una opción, ya que estoy trabajando en una aplicación heredada, no tengo el control del entorno de producción en ejecución, solo le estoy escribiendo un componente. Además, este "Readme for NChar How-to" establece que "esta conversión tiene un impacto sustancial en el rendimiento". Así que configurar todo para NChar por defecto cuando solo menos del 1% de mis tablas necesita esta conversión no es una opción inteligente.

Estoy usando el controlador fino de Oracle y tengo ojdbc6.jar y orai18n.jar en mi classpath.

Estoy buscando una solución JDBC estándar. No puedo usar ningún método o constantes con "oráculo" en ellos. OraclePreparedStatement no es una opción para mí.

Intenté usar Types.NVARCHAR con el servidor de MSSQL y funciona bien.

+0

¿Usted intentó utilizar setNString() y ver si funciona? –

+0

He editado mi pregunta con una actualización sobre setNString() –

+0

Para descartar lo obvio: ¿has intentado llamar al viejo y viejo 'setString()'? He almacenado con éxito caracteres árabes con eso. –

Respuesta

2

¡Encontré la solución!

Yo estaba usando ojdbc 11.2.0.1. Cuando cambié a 11.2.0.2, pude obtener setNString() funcionando correctamente. Pero sigo obteniendo el mismo java.sql.SQLException: Invalid column type si uso setObject() con Type.NVARCHAR. La culpa es tuya ... Oracle

De todos modos, la solución: cambiar a ojdbc 11.2.0.2

0

Me las arreglé para hacerlo funcionar hace algún tiempo con los siguientes conjuros. Estos métodos son un extracto de una clase más grande.

import com.mchange.v2.c3p0.C3P0ProxyStatement; 
import oracle.jdbc.OraclePreparedStatement; 

    static { 
     try { 
      SET_FORM_OF_USE_METHOD = OraclePreparedStatement.class.getDeclaredMethod("setFormOfUse", new Class[] { Integer.TYPE, Short.TYPE }); 
     } catch (NoSuchMethodException ex) { 
      LOG.fatal("Can't find the setFormOfUse method", ex); 
      throw new ExceptionInInitializerError(ex); 
     } 
    } 


    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws SQLException { 
     if (st instanceof OraclePreparedStatement) { 
      ((OraclePreparedStatement)st).setFormOfUse(index, OraclePreparedStatement.FORM_NCHAR); 
     } else if (st instanceof C3P0ProxyStatement) { 
      try { 
       C3P0ProxyStatement c3p0St = (C3P0ProxyStatement) st; 
       c3p0St.rawStatementOperation(SET_FORM_OF_USE_METHOD, C3P0ProxyStatement.RAW_STATEMENT, new Object[]{index, OraclePreparedStatement.FORM_NCHAR}); 
      } catch (IllegalAccessException ex) { 
       throw new UnexpectedException("Error calling setFormOfUse through C3P0", ex); 
      } catch (IllegalArgumentException ex) { 
       throw new UnexpectedException("Error calling setFormOfUse through C3P0", ex); 
      } catch (InvocationTargetException ex) { 
       throw new UnexpectedException("Error calling setFormOfUse through C3P0", ex); 
      } 
     } else { 
      throw new IllegalArgumentException("Unkown PreparedStatement implementation: " + st.getClass() + ". Maybe an unknown connection pool is hiding the OraclePreparedStatement?"); 
     } 

     st.setString(index, (String) value); 
    } 

El método nullSafeSet está estructurado para trabajar directamente en instancias OraclePreparedStatement, o en C3P0ProxyStatement en caso de que tenga la agrupación de conexiones C3P0; se deberán usar otras opciones en caso de diferentes grupos.

Este método trabajó con el ojdbc14.jar de Oracle 10.2.0.4.

+1

El problema con esta solución es porque depende de Oracle. Estoy buscando algo estándar JDBC ya que nuestro sistema funciona tanto en el servidor MSSQL como en Oracle.Parece que el controlador JDBC de Microsoft es más compatible con Java que el "propietario" de Java. –

+0

En la medida en que implique ojdbc14.jar, probablemente no exista una forma estándar de jdbc para hacerlo. No estoy seguro acerca de la versión del controlador que está usando; de todos modos, si esto funciona, podría usarlo para Oracle, y volver a la forma estándar para todo lo demás. – Flavio

+2

Como podemos ver en "Nuevos métodos para los datos del tipo de juego de caracteres nacional en JDK 1.6", dicen "use el método setFormOfUse ... ... se desaconseja porque este método quedará obsoleto en futuras versiones" y también dicen: " Si se utiliza el método setObject, entonces el tipo de datos de destino debe especificarse como Types.NCHAR, Types.NCLOB, Types.NVARCHAR o Types.LONGNVARCHAR " –

Cuestiones relacionadas