尝试迁移到 MySQL Connector/J 8.1.0 和我的
CallableStatement
代码在版本 5.1.49 下工作正常失败,并显示:
SQLException: Parameter number 2 is not an OUT parameter
程序:
CREATE PROCEDURE get_system_setting(IN p_setting VARCHAR(200), OUT message_out VARCHAR(200))
BEGIN
SELECT setting, value, message_out FROM SYSTEM_SETTING WHERE setting = p_setting;
END;
Java 代码示例:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class CallableTest {
/* MySQL Connector/J 8.1.0 (fails on all 8.*.* versions) */
private static final String DB_DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
/* MySQL Connector/J 5.1.49 - comment line above and uncomment next line to use v5 */
//private static final String DB_DRIVER_CLASS = "com.mysql.jdbc.Driver";
private static final String DB_URL = "jdbc:mysql://localhost:3306/DB_NAME?useSSL=false";
private static final String DB_USERNAME = "user";
private static final String DB_PASSWORD = "password";
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName(DB_DRIVER_CLASS);
conn = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void main(String[] args) {
Connection conn = null;
CallableStatement cs = null;
try {
conn = CallableTest.getConnection();
cs = conn.prepareCall("{call DB_NAME.get_system_setting(?, ?)}");
cs.setString(1, "CONNECT_TIMEOUT");
cs.registerOutParameter(2, Types.VARCHAR); // <-- Fails here
cs.execute();
String message = cs.getString(2);
if(message != null) {
System.out.printf("out parameter: %s\n", message);
} else {
ResultSet rs = cs.getResultSet();
boolean rowsReturned = ((rs != null) && rs.next());
if (rowsReturned) {
String setting = rs.getString("setting");
String value = rs.getString("value");
System.out.printf("setting: %s, value: %s\n", setting, value);
}
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
cs.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用 8.1.0 和所有 8.0.* 版本的连接器/j 时,上述操作会失败
java -cp .:mysql-connector-j-8.1.0.jar CallableTest
java.sql.SQLException: Parameter number 2 is not an OUT parameter
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:130)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:98)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:90)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:64)
at com.mysql.cj.jdbc.CallableStatement.checkIsOutputParam(CallableStatement.java:645)
at com.mysql.cj.jdbc.CallableStatement.registerOutParameter(CallableStatement.java:1717)
at com.mysql.cj.jdbc.CallableStatement.registerOutParameter(CallableStatement.java:1725)
at CallableTest.main(CallableTest.java:49)
但适用于 5.1.49
java -cp .:mysql-connector-java-5.1.49.jar CallableTest
setting: CONNECT_TIMEOUT, value: 10000
尝试了命名参数和索引参数。查看 Connector/J 文档,找不到任何对版本之间 CallableStatement 的特定更改的引用。
环境
事实证明,该数据库模式中有一个与过程同名的函数...MySQL 允许使用相同的对象名称来声明函数和过程。似乎不应该允许这种情况,因为其他数据库就是这种情况。此外,错误消息有些误导性。与 Oracle 一起打开了错误报告。