Arm*_*ile 6 sql-server parameters stored-procedures jdbc mssql-jdbc
在 SQL Server 2016 的一个实例中,我有一个包含数十个参数的存储过程。例如:
CREATE PROCEDURE spName (
@par1 INT = NULL,
@par2 VARCHAR(10) = NULL,
....
....
@par98 INT = NULL,
@par99 INT = NULL,
) AS
BEGIN
....
....
END
Run Code Online (Sandbox Code Playgroud)
我有一个用 C# 编写的客户端,它调用仅指定带有值的参数的存储过程。前任:
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "spName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = dbConn;
cmd.Parameters.Add(new SqlParameter("par1", "val1"));
cmd.Parameters.Add(new SqlParameter("par47", "val47"));
...
cmd.ExecuteNonQuery();
Run Code Online (Sandbox Code Playgroud)
它工作完美!因此,该过程被执行,并且只有 2 个参数(par1 和 par47)具有值。其他参数保持默认值(NULL)。
我会从使用 Microsoft JDBC 驱动程序 6.2 的 Java 客户端执行相同的操作。我用 指定参数List<Map<String, Object>>,所以有一个参数名称-->参数值的列表。以下方法构建PreparedStatement对象:
private CallableStatement prepareStatement(String spName, Map<String, ?> parameters) throws SQLException {
setupConnection();
CallableStatement stmt = null;
try {
stmt = conn.prepareCall(getSpCallString(spName, parameters));
if (parameters != null) {
for (String parName : parameters.keySet())
stmt.setObject(parName, parameters.get(parName));
}
} catch (SQLException e) {
ApplicationLogging.severe("Cannot prepare callable statement", e);
throw e;
}
return stmt;
}
Run Code Online (Sandbox Code Playgroud)
getSpCallString() 方法生成一个类型的字符串{ call spName ?,?, ... , ? },?其数量与传递给过程的参数数量相同,因此不是所有 99 个参数。如果我有 2 个参数,它会生成字符串{ call spName ?,? }。通过传递例如 par15=val15 和 par47=val47 ,它会引发以下异常:
com.microsoft.sqlserver.jdbc.SQLServerException: The index 2 is out of range.
Run Code Online (Sandbox Code Playgroud)
我可以解决这个问题,将调用命令中的参数数量?与存储过程的参数数量相同,但是......我不知道每个存储过程的参数数量(及其位置)!在 C# 中,这个问题可以简单解决,因为参数仅分配其名称,因此参数的数量和顺序实际上可以是一个黑盒子。
我可以用Java以某种方式做到这一点吗?
这是mssql-jdbc 驱动程序中命名参数支持的当前实现中已确认的缺陷CallableStatement。尽管 JDBC 4.2 规范第 13.3.2 节指出......
命名参数可用于仅指定没有默认值的值。
...我们似乎需要为每个可能的参数提供一个参数占位符,并且似乎没有办法指定DEFAULT我们可能简单省略的参数。
作为解决方法,我们可以使用这样的代码
public static ResultSet executeStoredProcedureQuery(
Connection conn, String spName, Map<String, Object> paramItems)
throws SQLException {
StringBuffer sqlBuf = new StringBuffer("EXEC ");
sqlBuf.append(spName);
int paramCount = 1;
for (String paramName : paramItems.keySet()) {
sqlBuf.append(
(paramCount++ > 1 ? ", " : " ") +
(paramName.startsWith("@") ? "" : "@") + paramName + "=?");
}
String sql = sqlBuf.toString();
myLogger.log(Level.INFO, sql);
// e.g., EXEC dbo.BreakfastSP @helpings=?, @person=?, @food=?
PreparedStatement ps = conn.prepareStatement(sql);
paramCount = 1;
for (String paramName : paramItems.keySet()) {
ps.setObject(paramCount++, paramItems.get(paramName));
}
return ps.executeQuery();
}
Run Code Online (Sandbox Code Playgroud)
我们可以这样称呼
// test data
Map<String, Object> paramItems = new HashMap<>();
paramItems.put("@person", "Gord");
paramItems.put("@food", "bacon");
paramItems.put("@helpings", 3);
//
ResultSet rs = executeStoredProcedureQuery(conn, "dbo.BreakfastSP", paramItems);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3391 次 |
| 最近记录: |