使用 spring StoredProcedure 将参数输出为 Integer
Output parameter as Integer using spring StoredProcedure
我试图将 Oracle 存储过程的输出参数存储在我的变量中,但我遇到了这个问题:
java.math.BigDecimal cannot be cast to java.lang.Integer
我正在使用 org.springframework.jdbc.object
中的 StoredProcedure
执行方法 returns a Map<String, Object>
然后我做这样的事情
Integer proposalId = procedure.execute().get("po_proposal_id");
其中 po_proposal_id 在 PROCEDURE 中定义为
po_proposal_id Out Number,
我知道我可以做这样的事情:
Integer proposalId = ((BigDecimal)
procedure.execute().get("po_proposal_id")).intValue();
但我不想。我为什么要那么做? Spring StoredProcedure 中的执行方法是否总是将 Number SQL 参数映射为 BigDecimal?
我已尝试将过程中的参数声明为
po_proposal_id Out Integer,
但运气不好。
而且我还尝试更改将 Java 中的输出参数从 oracle.types.Number 映射到 oracle.types.Integer 的方式,但没有成功。
我发现这个 table Table 3-1 SQL and PL/SQL Data Type to Oracle and JDBC Mapping Classes(你需要向下滚动一点)它显示了 oracle 数据类型和 java 之间的映射,但我似乎不能让它工作。
嗨,格罗贾,
我会尝试回答我对 Spring StoredProcedure class 做了一些无聊的分析,当你调用 StoredProcedure class 的执行方法时,它会调用下面的方法
getJdbcTemplate().call(newCallableStatementCreator(inParams), getDeclaredParameters())
经过一系列调用,它最终调用了 ResultSet class 的 getObject(int column index) 方法,它依赖于 oracle 的数据库提供程序,mysql 它完全不同,这个方法负责对于 returning 对象的数据类型,这是由 Column Row Mapper 调用的,它映射每个列名的列以及使用 StoredProcedure Class
的相应值
**Column Row Mapper Class :**
@Override
public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
Map<String, Object> mapOfColumnValues = createColumnMap(columnCount);
for (int i = 1; i <= columnCount; i++) {
String column = JdbcUtils.lookupColumnName(rsmd, i);
mapOfColumnValues.put(getColumnKey(column), getColumnValue(rs, i));
}
return mapOfColumnValues;
}
getColumnValue(rs, i) 负责调用getResultSetValue(ResultSet rs, int index) 方法负责调用resultSet 的getObject(int column index) 实际确定数据类型returned.
代码示例:
public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {
Object obj = rs.getObject(index);
String className = null;
if (obj != null) {
className = obj.getClass().getName();
}
if (obj instanceof Blob) {
Blob blob = (Blob) obj;
obj = blob.getBytes(1, (int) blob.length());
}
else if (obj instanceof Clob) {
Clob clob = (Clob) obj;
obj = clob.getSubString(1, (int) clob.length());
}
else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
obj = rs.getTimestamp(index);
}
else if (className != null && className.startsWith("oracle.sql.DATE")) {
String metaDataClassName = rs.getMetaData().getColumnClassName(index);
if ("java.sql.Timestamp".equals(metaDataClassName) || "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
obj = rs.getTimestamp(index);
}
else {
obj = rs.getDate(index);
}
}
else if (obj instanceof java.sql.Date) {
if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
obj = rs.getTimestamp(index);
}
}
return obj;
}
所以真正的问题是为什么只有它的 returning BigDecimal Type ResultSet 的 getObject(int column index) 方法 class 正在为 oracle 驱动程序调用以下方法
Datum var4 = this.getOracleObject(var1)
它根据列的各个数据类型调用不同的访问器,并且每个访问器都在您的案例中实现了 getObject oracle 考虑所有数据类型,例如 int、float 作为数字数据类型参考 https://www.techonthenet.com/oracle/datatypes.php
所以它使用 NumberCommonAccessor,它总是 return BigDecimal 用于所有数据类型,如 int、float 所以你有 显式类型转换 并且你将一如既往地接收数据类型 BigDecimal。它不依赖于指定您需要来自存储过程的一些输出参数列表的 SqlOutParameter,它对数据类型没有影响。
您可以通过调用storedProcedure.declareParameter(SqlParameter param)
来注册参数声明
SqlParameter 有很多构造函数,其中一个包含 org.springframework.jdbc.core.SqlReturnType
接口,因此您可以创建自己的 ReturnType:
public class IntegerReturnType implements SqlReturnType {
@Override
public Object getTypeValue(
final CallableStatement cs,
final int paramIndex,
final int sqlType,
final String typeName
)
throws SQLException {
return cs.getInt(paramIndex);
}
}
终于可以声明它并调用过程了:
storedProcedure.declareParameter(
new SqlOutParameter(
"PO_PROPOSAL_ID", // in Oracle prefers upper case letters
Types.NUMERIC,
null,
new IntegerReturnType()
)
);
final Integer result = (Integer)(storedProcedure.execute().get("PO_PROPOSAL_ID")); // Oracle prefers upper case letters
我试图将 Oracle 存储过程的输出参数存储在我的变量中,但我遇到了这个问题:
java.math.BigDecimal cannot be cast to java.lang.Integer
我正在使用 org.springframework.jdbc.object
中的 StoredProcedure
执行方法 returns a Map<String, Object>
然后我做这样的事情
Integer proposalId = procedure.execute().get("po_proposal_id");
其中 po_proposal_id 在 PROCEDURE 中定义为
po_proposal_id Out Number,
我知道我可以做这样的事情:
Integer proposalId = ((BigDecimal)
procedure.execute().get("po_proposal_id")).intValue();
但我不想。我为什么要那么做? Spring StoredProcedure 中的执行方法是否总是将 Number SQL 参数映射为 BigDecimal?
我已尝试将过程中的参数声明为
po_proposal_id Out Integer,
但运气不好。
而且我还尝试更改将 Java 中的输出参数从 oracle.types.Number 映射到 oracle.types.Integer 的方式,但没有成功。
我发现这个 table Table 3-1 SQL and PL/SQL Data Type to Oracle and JDBC Mapping Classes(你需要向下滚动一点)它显示了 oracle 数据类型和 java 之间的映射,但我似乎不能让它工作。
嗨,格罗贾, 我会尝试回答我对 Spring StoredProcedure class 做了一些无聊的分析,当你调用 StoredProcedure class 的执行方法时,它会调用下面的方法
getJdbcTemplate().call(newCallableStatementCreator(inParams), getDeclaredParameters())
经过一系列调用,它最终调用了 ResultSet class 的 getObject(int column index) 方法,它依赖于 oracle 的数据库提供程序,mysql 它完全不同,这个方法负责对于 returning 对象的数据类型,这是由 Column Row Mapper 调用的,它映射每个列名的列以及使用 StoredProcedure Class
的相应值**Column Row Mapper Class :**
@Override
public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
Map<String, Object> mapOfColumnValues = createColumnMap(columnCount);
for (int i = 1; i <= columnCount; i++) {
String column = JdbcUtils.lookupColumnName(rsmd, i);
mapOfColumnValues.put(getColumnKey(column), getColumnValue(rs, i));
}
return mapOfColumnValues;
}
getColumnValue(rs, i) 负责调用getResultSetValue(ResultSet rs, int index) 方法负责调用resultSet 的getObject(int column index) 实际确定数据类型returned.
代码示例:
public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {
Object obj = rs.getObject(index);
String className = null;
if (obj != null) {
className = obj.getClass().getName();
}
if (obj instanceof Blob) {
Blob blob = (Blob) obj;
obj = blob.getBytes(1, (int) blob.length());
}
else if (obj instanceof Clob) {
Clob clob = (Clob) obj;
obj = clob.getSubString(1, (int) clob.length());
}
else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
obj = rs.getTimestamp(index);
}
else if (className != null && className.startsWith("oracle.sql.DATE")) {
String metaDataClassName = rs.getMetaData().getColumnClassName(index);
if ("java.sql.Timestamp".equals(metaDataClassName) || "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
obj = rs.getTimestamp(index);
}
else {
obj = rs.getDate(index);
}
}
else if (obj instanceof java.sql.Date) {
if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
obj = rs.getTimestamp(index);
}
}
return obj;
}
所以真正的问题是为什么只有它的 returning BigDecimal Type ResultSet 的 getObject(int column index) 方法 class 正在为 oracle 驱动程序调用以下方法
Datum var4 = this.getOracleObject(var1)
它根据列的各个数据类型调用不同的访问器,并且每个访问器都在您的案例中实现了 getObject oracle 考虑所有数据类型,例如 int、float 作为数字数据类型参考 https://www.techonthenet.com/oracle/datatypes.php 所以它使用 NumberCommonAccessor,它总是 return BigDecimal 用于所有数据类型,如 int、float 所以你有 显式类型转换 并且你将一如既往地接收数据类型 BigDecimal。它不依赖于指定您需要来自存储过程的一些输出参数列表的 SqlOutParameter,它对数据类型没有影响。
您可以通过调用storedProcedure.declareParameter(SqlParameter param)
SqlParameter 有很多构造函数,其中一个包含 org.springframework.jdbc.core.SqlReturnType
接口,因此您可以创建自己的 ReturnType:
public class IntegerReturnType implements SqlReturnType {
@Override
public Object getTypeValue(
final CallableStatement cs,
final int paramIndex,
final int sqlType,
final String typeName
)
throws SQLException {
return cs.getInt(paramIndex);
}
}
终于可以声明它并调用过程了:
storedProcedure.declareParameter(
new SqlOutParameter(
"PO_PROPOSAL_ID", // in Oracle prefers upper case letters
Types.NUMERIC,
null,
new IntegerReturnType()
)
);
final Integer result = (Integer)(storedProcedure.execute().get("PO_PROPOSAL_ID")); // Oracle prefers upper case letters