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