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