1. 复现问题
今天在调试接口时,突然报出如下错误:
java">org.springframework.jdbc.BadsqlGrammarException:
### Error querying database. Cause: java.sql.SQLException: No value specified for parameter 1
### The error may exist in ***/test/cloud/lowcode/mapper/AppCustom***ponentVersionMapper.java (best guess)
### The error may involve ***.test.cloud.lowcode.mapper.AppCustom***ponentVersionMapper.getMaxVersion-Inline
### The error o***urred while setting parameters
### SQL: SELECT IFNULL(MAX(version),1.0) from app_custom_***ponent_version WHERE app_custom_***ponent_id = ?;
### Cause: java.sql.SQLException: No value specified for parameter 1
; bad SQL grammar []; nested exception is java.sql.SQLException: No value specified for parameter 1
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
at ***.sun.proxy.$Proxy157.selectOne(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160)
at ***.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:89)
at ***.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148)
at ***.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
at ***.sun.proxy.$Proxy182.getMaxVersion(Unknown Source)
at ***.test.cloud.lowcode.service.AppCustom***ponentService.getMaxVersion(AppCustom***ponentService.java:35)
at ***.test.cloud.lowcode.service.AppCustom***ponentService$$FastClassBySpringCGLIB$$a271163e.invoke(<generated>)
.....
即Error querying database. Cause: java.sql.SQLException: No value specified for parameter 1
的错误。
2. 分析问题
正赶上最近ChatGPT
很火,于是借助ChatGPT
来解决我的问题,如下所示:
This error generally o***urs when a parameter is not supplied in the query or when an incorrect number of parameters are provided. To fix this error, check that the correct number of parameters are supplied and that all parameters have a value specified. Additionally, ensure that the values passed as parameters match the data type of the associated column.
可惜的是,ChatGPT
给出英文的结果,不妨将其翻译成中文,如下所示:
当查询中未提供参数或提供的参数数量不正确时,通常会发生此错误。若要修复此错误,请检查是否提供了正确数量的参数,以及是否指定了所有参数的值。此外,请确保作为参数传递的值与关联列的数据类型匹配。
根据翻译结果可知未提供参数或提供的参数数量不正确
。
再回头看我的错误栈信息,如下图所示:
定位是AppCustom***ponentVersionMapper
类的getMaxVersion
方法出现了错误,如下代码所示:
@Mapper
public interface AppCustom***ponentVersionMapper extends BaseMapper<AppCustom***ponentVersion> {
/**
* 获取当前组件下最大的版本号
*
* @author super先生
* @datetime 2023/2/17:16:53
* @param ***ponentId 组件ID
* @return
*/
@Select(
"SELECT "
+ " IFNULL( MAX( version ), 1.0 ) "
+ "FROM "
+ " app_custom_***ponent_version "
+ "WHERE "
+ " app_custom_***ponent_id = ? "
+ " AND deleted = 0")
float getMaxVersion(@Param("***ponentId") Long ***ponentId);
}
仔细排查@Select
注解中的SQL
语句,突然发现app_custom_***ponent_id = ?
这里语法错误。
我使用的是mybatis
框架,即便参数***ponentId
有实际值,mybatis
将也无法将值传进去。
因为mybatis
表示占位符的语法是#{变量}
,而非问号(?
),因而,mybatis
生成的SQL语句如下:
SELECT
IFNULL(MAX(version), 1.0)
FROM
app_custom_***ponent_version
WHERE
app_custom_***ponent_id = ?
AND deleted = 0
这样的SQL
语句,jdbc
无法执行(mybatis
的底层是jdbc
),才会报出 No value specified for parameter 1
错误。
3. 解决问题
既然知道我的变量语法错误,按照mybatis
的语法修改即可,
也就是将app_custom_***ponent_id = ?
修改为app_custom_***ponent_id = #{***ponentId}
,如下代码所示:
@Mapper
public interface AppCustom***ponentVersionMapper extends BaseMapper<AppCustom***ponentVersion> {
/**
* 获取当前组件下最大的版本号
*
* @author super先生
* @datetime 2023/2/17:16:53
* @param ***ponentId 组件ID
* @return
*/
@Select(
"SELECT "
+ " IFNULL( MAX( version ), 1.0 ) "
+ "FROM "
+ " app_custom_***ponent_version "
+ "WHERE "
+ " app_custom_***ponent_id = #{***ponentId} "
+ " AND deleted = 0")
float getMaxVersion(@Param("***ponentId") Long ***ponentId);
}
此时,重新启动spring boot
服务,调用getMaxVersion
方法,SQL
即可成功运行。
4. 出现该错误的其他可能
正如上文所述,出现这种错误,一般情况下是变量语法的错误,导致框架无法获取到实参。
因而,我们在开发时,一定要注意变量语法。
如果你使用的是jdbc
的executeQuery()
方法,一定不要忘了传参,如下图所示:
你会看到:statement.setString(1,username)
已被注释,自然无参数可传。
因而,我们需要取消注释,如下图所示:
jdbc
才能正常执行sql
语句。