如何用Java的R2DBC调用带输入输出参数的SQL Server存储过程?
解决R2DBC调用SQL Server存储过程的问题
一、SQL Server存储过程调用的核心语法要点
SQL Server的R2DBC驱动遵循以下规则:
- 参数占位符必须使用
@前缀 - 输出参数必须在SQL语句中显式标注
OUTPUT关键字
二、修复DatabaseClient调用方式
修正后的代码
public Mono<Integer> callProcedureWithDatabaseClient() { return databaseClient.sql("CALL MY_SCHEMA.MY_PROCEDURE(@Prm1, @Prm2 OUTPUT)") .bind("@Prm1", "Some text to save in database") .execute() .flatMap(result -> result.getOutParameters()) .map(outParams -> outParams.get("Prm2", Integer.class)) .doOnSuccess(outputValue -> log.info("输出参数Prm2的值: {}", outputValue)) .doOnError(error -> log.error("调用存储过程失败", error)); }
关键修正说明
- 参数占位符修正:将原SQL中的
Prm1改为@Prm1,让R2DBC驱动能识别到绑定参数 - 输出参数标识:添加
OUTPUT关键字声明@Prm2为输出参数 - 结果处理逻辑:放弃
fetch().all(),改用execute()配合getOutParameters()直接获取输出参数,而非处理结果集 - 响应式规范:返回
Mono<Integer>替代直接return 0,符合Reactive编程模型,便于上层调用者处理异步结果
三、修复Connection.createStatement调用方式
修正后的代码
public Mono<Integer> callProcedureWithConnection() { return ConnectionFactoryUtils.getConnection(connectionFactory) .flatMap(connection -> connection.createStatement("CALL MY_SCHEMA.MY_PROCEDURE(@Prm1, @Prm2 OUTPUT)") .bind("@Prm1", Parameters.in(R2dbcType.NVARCHAR, "bacabacabacabacabacn")) .bind("@Prm2", Parameters.out(R2dbcType.INTEGER)) .execute() .flatMap(result -> result.getOutParameters()) .map(outParams -> outParams.get("Prm2", Integer.class)) .doFinally(signalType -> ConnectionFactoryUtils.releaseConnection(connection, connectionFactory))) .doOnSuccess(outputValue -> log.info("输出参数Prm2的值: {}", outputValue)) .doOnError(error -> log.error("调用存储过程失败", error)); }
关键修正说明
- SQL语句规范:统一使用
@占位符并添加OUTPUT关键字 - 参数绑定修正:去掉绑定参数名中的冒号,直接使用
@Prm1匹配SQL中的占位符 - 资源管理:添加
doFinally确保数据库连接被正确释放,避免资源泄漏 - 输出参数获取:通过
result.getOutParameters()提取输出参数集合,再获取指定参数的值
额外注意事项
- 确保使用的R2DBC SQL Server驱动为最新稳定版本,避免兼容性问题
- 存储过程的参数名称需与代码中绑定的
Prm1、Prm2完全一致(大小写敏感取决于SQL Server的配置) - 若存储过程位于默认Schema(如dbo),可省略
MY_SCHEMA.前缀,但明确指定Schema能避免歧义
内容的提问来源于stack exchange,提问作者bkk
相关产品推荐
相关产品推荐

