SimpleJdbcCall调用PostgreSQL存储过程未使用当前配置schema问题
问题表现
- 数据库连接通过yaml配置,JDBC连接串为
jdbc:postgresql://localhost:5455/userdb?currentSchema=customschema,指定连接默认schema为customschema - 所有通过
jdbcTemplate直接执行的查询语句,都能正确使用配置的customschema - 仅通过
SimpleJdbcCall发起的存储过程/函数调用,会默认使用PostgreSQL的publicschema - 调试阶段打印
jdbcTemplate.getDataSource().getConnection().getSchema()返回值为customschema,确认连接本身的schema配置生效 - 必须显式调用
.withSchemaName("customschema")强制指定schema,才能让存储过程调用在customschema下执行,官方文档未查询到该行为的相关说明
原因说明
该行为不属于Spring框架缺陷,是两套执行路径的逻辑差异导致:
- 直接通过
jdbcTemplate执行SQL时,走的是PostgreSQL连接本身的search_path解析逻辑,会读取连接串中配置的currentSchema参数,所以普通查询可以正常命中目标schema SimpleJdbcCall在执行存储过程前,会先通过JDBC驱动提供的元数据接口检索存储过程的参数、返回值定义,PostgreSQL JDBC驱动实现的元数据检索接口,默认不会继承连接级别的currentSchema配置做检索范围过滤,默认仅扫描publicschema下的存储过程对象,因此会出现找不到目标schema下存储过程、回退到public schema执行的问题。
解决方法
- 稳定无兼容问题的实现方式:初始化
SimpleJdbcCall时显式调用.withSchemaName("customschema")指定目标schema,示例代码如下:
// 未指定schema时默认检索public schema下的存储过程 new SimpleJdbcCall(jdbcTemplate) .withFunctionName("custom_stored_procedure_name") .execute(); // 显式指定schema后可正常调用customschema下的存储过程 new SimpleJdbcCall(jdbcTemplate) .withSchemaName("customschema") .withFunctionName("custom_stored_procedure_name") .execute();
- 全局统一配置方式:如果项目中存在大量
SimpleJdbcCall调用场景,可以封装SimpleJdbcCall工厂类,统一设置默认schema,避免每个调用点重复声明 - 数据库侧配置方式:给连接使用的数据库用户配置全局搜索路径,执行SQL
ALTER ROLE <实际业务使用的数据库用户名> SET search_path TO customschema,public;,让元数据检索阶段也能扫描到customschema下的对象
内容的提问来源于stack exchange,提问作者Hyukchan Kwon
相关产品推荐
相关产品推荐

