代码之家  ›  专栏  ›  技术社区  ›  L. Holanda

使用Types.NVARCHAR和oracle JDBC驱动程序处理西里尔字符

  •  6
  • L. Holanda  · 技术社区  · 15 年前

    我想用 "New Methods for National Character Set Type Data in JDK 1.6" ,以获得 标准JDBC 处理西里尔字符的解决方案,但当执行到达NVARCHAR类型的任何行时,例如:

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

    然后我得到一个例外:

    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)
    

    我还尝试使用setNString(),但出现了一个更奇怪的异常:

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

    如果我使用java-Doracle.jdbc.defaultNChar=true myApplication和regular Types.VARCHAR,俄语单词将被正确存储。但是使用-Doracle.jdbc.defaultNChar=true不是一个选项,因为我正在处理一个遗留应用程序,我无法控制生产环境的运行,我只是在向它编写一个组件。此外,这个 "Readme for NChar How-to" 声明“此转换对性能有重大影响”。因此,当只有不到1%的表需要这种转换时,默认将所有设置为NChar不是明智的选择。

    我使用的是oracle瘦驱动程序,类路径中有ojdbc6.jar和orai18n.jar。

    我正在寻找一个标准的JDBC解决方案。我不能使用任何带有“oracle”的方法或常量。OraclePreparedStatement不是我的选择。

    我尝试在MSSQL服务器上使用Types.NVARCHAR,结果运行良好。

    2 回复  |  直到 15 年前
        1
  •  2
  •   L. Holanda    15 年前

    我找到了解决办法!

    我用的是OJDBC11.2.0.1。当我切换到11.2.0.2时,我可以 setNString() 工作正常。 但我还是一样 java.sql.SQLException: Invalid column type 如果我用 setObject() 具有 Type.NVARCHAR . 你真可耻,先知。。。

    无论如何,解决方案:切换到OJDBC11.2.0.2

        2
  •  0
  •   Flavio    15 年前

    前一段时间我用了下面的咒语。这些方法是一个更大类的摘录。

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

    nullSafeSet方法的结构是直接在OraclePreparedStatement实例上工作,或者在拥有C3P0连接池的情况下在C3P0ProxyStatement上工作;对于不同的池,必须使用其他选项。

    此方法适用于Oracle 10.2.0.4中的ojdbc14.jar。

    推荐文章