Я использую эти библиотеки
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
и этот класс
CallableStatementCreatorFactory
Подробное исключение
Root Cause: [org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{? = call xxxxxxxxxxxx()}]; SQL state [99999]; error code [17004]; Invalid coloumn: 16; nested exception is java.sql.SQLException: Invalid coloumn: 16]</faultstring>
Map<String, Object> result = QueryExecutor.getInstance().executeStoredProcedure("XXX", null);
Не поняли основную причину, по которой мы получаем эту ошибку?
Кажется, ваша функция возвращает значение BOOLEAN
. Драйвер Oracle JDBC не поддерживает значения BOOLEAN
.
Следующий класс воспроизводит аналогичную ошибку:
import java.sql.*;
import oracle.jdbc.OracleTypes;
public class Error17004Test {
public static void main(String[] args) throws Exception {
try (Connection c = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:XE", "user", "password")) {
try (Statement stmt = c.createStatement()) {
stmt.execute(
"CREATE OR REPLACE FUNCTION bool_test RETURN BOOLEAN " +
"AS BEGIN RETURN TRUE; END;");
}
try (CallableStatement cstmt = c.prepareCall("{ ? = call bool_test }")) {
cstmt.registerOutParameter(1, OracleTypes.BOOLEAN);
cstmt.execute();
System.out.println("Got result of " + cstmt.getObject(1));
}
}
catch (SQLException e) {
System.out.println("Got a SQLException with message '" + e.getMessage() +
"' and error code " + e.getErrorCode());
}
}
}
Когда я запускаю это, я получаю следующий вывод:
Got a SQLException with message 'Invalid column type: 16' and error code 17004
К счастью, есть простой способ: оберните свою функцию вызовом sys.diutil.bool_to_int
. sys.diutil.bool_to_int
преобразует значения BOOLEAN
TRUE
, FALSE
и NULL
в 1
, 0
и NULL
соответственно. Затем вам просто нужно прочитать целочисленное значение из вызова хранимой процедуры вместо логического. Конечно, вам нужно сделать преобразование между возвращаемым целочисленным значением и логическим значением, которое вы, вероятно, хотели, но это должно быть просто.
Если я возьму свой класс выше и заменим две строки
try (CallableStatement cstmt = c.prepareCall("{ ? = call bool_test }")) {
cstmt.registerOutParameter(1, OracleTypes.BOOLEAN);
с
try (CallableStatement cstmt = c.prepareCall(
"{ ? = call sys.diutil.bool_to_int(bool_test) }")) {
cstmt.registerOutParameter(1, Types.INTEGER);
и снова запустите мой класс, я получаю следующий вывод:
Got result of 1
вместо.
Проверьте, нет ли несоответствия между типами данных и убедитесь, что нет нулевых значений или ограничений.