Oracle 数据库

Oracle 存在许多问题。以下是解决这些问题的方法。

假设你的过程输出参数是 ref cursor,你将得到此异常。

java.sql.SQLException:列类型无效:2012

所以在 simpleJdbcCall.declareParameters() 中将 Types.REF_CURSOR 更改为 OracleTypes.CURSOR ****

支持 OracleTypes

如果数据中包含某些列类型,则可能只需要执行此操作。

我遇到的下一个问题是,诸如 oracle.sql.TIMESTAMPTZ 之类的专有类型在 SqlRowSetResultSetExtractor 中导致了这个错误:

列的 SQL 类型无效; 嵌套异常是 java.sql.SQLException:列的 SQL 类型无效

所以我们需要创建一个支持 Oracle 类型的 ResultSetExtractor
我将在此代码后解释密码的原因。

package com.boost.oracle;

import oracle.jdbc.rowset.OracleCachedRowSet;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * OracleTypes can cause {@link org.springframework.jdbc.core.SqlRowSetResultSetExtractor}
 * to fail due to a Oracle SQL type that is not in the standard {@link java.sql.Types}.
 *
 * Also, types such as {@link oracle.sql.TIMESTAMPTZ} require a Connection when processing
 * the ResultSet; {@link OracleCachedRowSet#getConnectionInternal()} requires a JNDI
 * DataSource name or the username and password to be set.
 *
 * For now I decided to just set the password since changing SpringBoot to a JNDI DataSource
 * configuration is a bit complicated.
 *
 * Created by Arlo White on 2/23/17.
 */
public class OracleSqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet> {

    private String oraclePassword;

    public OracleSqlRowSetResultSetExtractor(String oraclePassword) {
        this.oraclePassword = oraclePassword;
    }

    @Override
    public SqlRowSet extractData(ResultSet rs) throws SQLException, DataAccessException {
        OracleCachedRowSet cachedRowSet = new OracleCachedRowSet();
        // allows getConnectionInternal to get a Connection for TIMESTAMPTZ
        cachedRowSet.setPassword(oraclePassword);
        cachedRowSet.populate(rs);
        return new ResultSetWrappingSqlRowSet(cachedRowSet);
    }

}

某些 Oracle 类型需要 Connection 才能从 ResultSet 获取列值。TIMESTAMPTZ 是这些类型之一。因此,当调用 rowSet.getTimestamp(colIndex) 时,你将获得以下异常:

引发者:java.sql.SQLException:未在 oracle.jdbc.rowset.OracleCachedRowSet.getTimestamp(OracleCachedRowSet.java) 的 oracle.jdbc.rowset.OracleCachedRowSet.getConnectionInternal(OracleCachedRowSet.java:560)中设置一个或多个身份验证 RowSet 属性。 :3717)at org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet.getTimestamp

如果你深入研究此代码,你将看到 OracleCachedRowSet 需要密码或 JNDI DataSource 名称才能获得 Connection。如果你更喜欢 JNDI 查找,只需验证 OracleCachedRowSet 是否设置了 DataSourceName。

所以在我的服务中,我在密码中自动装配并声明输出参数,如下所示:

new SqlOutParameter("cursor_param_name", OracleTypes.CURSOR, new OracleSqlRowSetResultSetExtractor(oraclePassword))