当我尝试使用 SQLXML 而不是 XMLType 作为 Oracle 函数的输出类型时出现 SQLException

SQLException when I try to use SQLXML instead of XMLType as output type from Oracle function

我正在尝试重构我的 SpringBoot 应用程序并使用 XMLType 代替 java.sql.SQLXML,因为一些与 XMLType 相关的方法已经被弃用,我想重写它。

我在文档中发现我应该 - 而不是弃用:

Document doc = xmltype.getDocument();

使用:

DOMSource domSource = sqlxml.getSource (DOMSource.class);
Document document = (Document) domSource.getNode();

但我对此有疑问。当我尝试这样做时,出现异常。

这是我的代码片段:

            String xmlInStr;  
            XMLType xmlIn = null;  
            XMLType xmlOut = null;  
            SQLXML sqlxmlIn = null;  
            SQLXML sqlxmlOut = null;  
            OracleConnection conn = null;  
            Connection hikariConn = null;  
    (...)  
            try {  
                hikariConn = jdbcTemplate.getDataSource().getConnection();  
                sqlxmlIn = hikariConn.createSQLXML();  
                sqlxmlIn.setString(xmlInStr);  
                logger.debug("Input xml has been set.");  
                // input params  
                SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)  
      
                    .withFunctionName("getQuestionnaireByType")  
                    .withReturnValue()  
                    .withoutProcedureColumnMetaDataAccess()  
                    .declareParameters(  
                            new SqlOutParameter("RETURN",OracleTypes.SQLXML),  
                            new SqlParameter("vLang",OracleTypes.VARCHAR),  
                            new SqlParameter("vRefId",OracleTypes.VARCHAR),  
                            new SqlParameter("vSrcId",OracleTypes.VARCHAR),  
                            new SqlParameter("vUserId",OracleTypes.VARCHAR),  
                            new SqlParameter("vQueType",OracleTypes.VARCHAR),  
                            new SqlParameter("vXmlDataIn",OracleTypes.SQLXML)  
                    )  
                ;  
                jdbcCall.setAccessCallParameterMetaData(false);  
                jdbcCall.setReturnValueRequired(true);  
                jdbcCall.withSchemaName("atr_adap");  
      
                SqlParameterSource in = new MapSqlParameterSource()  
                        .addValue("vLang", rhData.getLocale().getLanguage())  
                        .addValue("vRefId", rhData.getRequestId())  
                        .addValue("vSrcId", rhData.getSrcId())  
                        .addValue("vUserId", rhData.getUserId())  
                        .addValue("vQueType", queType)  
                        .addValue("vXmlDataIn", sqlxmlIn);  
                          
                // calling db (with XMLType)  
                xmlOut = jdbcCall.executeFunction(XMLType.class, in);  
                  
                logger.debug("Stored Procedure {} executed (XMLType)", jdbcCall.getProcedureName());  
                String xmlOutStr = null;  
                xmlOutStr = xmlOut.getString();  
                logger.info("xml out (XMLType)\r\n{}", xmlOutStr);  
                doc = xmlOut.getDocument(); // everything ok (but getDocument deprecated ...)  
                  
                // calling db (with SQLXML)  
                sqlxmlOut = jdbcCall.executeFunction(java.sql.SQLXML.class, in);  
                logger.debug("Stored Procedure {} executed (SQLXML)", jdbcCall.getProcedureName());  
                xmlOutStr = sqlxmlOut.getString();  
                logger.info("xml out (SQLXML)\r\n{}", xmlOutStr); // everything ok  
                DOMSource domSource = sqlxmlOut.getSource(DOMSource.class); // the following exception is throwing from here  
                doc = (Document) domSource.getNode();   
(...) 
java.sql.SQLException: Attempt to read a SQLXML that is not readable. 
    at oracle.xdb.XMLType.getSource(XMLType.java:5159)
    at my.package.JdbcQuestionnairesRepository.findByType(JdbcQuestionnairesRepository.java:239)
    at my.package.JdbcQuestionnairesRepository$$FastClassBySpringCGLIB$$a9555145.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at my.package.JdbcQuestionnairesRepository$$EnhancerBySpringCGLIB$$a184900c.findByType(<generated>)
    at my.package.QuestionnairesService.getQuestionnaireByType(QuestionnairesService.java:48)
(...)   

我做错了什么?

此致,
科里

问题似乎出在行 xmlOutStr = sqlxmlOut.getString(); 上。删除这一行,以及将 xmlOutStr 写入日志的行,您的代码应该可以工作。

JavaDoc for the JDBC SQLXML interface 还提到了以下内容:

The state moves from readable to not readable once free() or any of the reading APIs are called: getBinaryStream(), getCharacterStream(), getSource(), and getString().

我不能说为什么 XMLType.getDocument() 即使在调用 .getString() 之后也不会抛出异常。