MyBatis如何为所有查询传递默认参数(Spring Boot加密解密场景)
问题核心原因
当前参数无法传入查询的本质是MyBatis的取值机制不匹配:
- MyBatis 配置类
Configuration下的variables全局变量集合,仅支持${}语法的静态SQL文本替换逻辑,完全不会被#{}预编译参数占位符识别 - 你SQL里写的
#{secretKey}属于预编译参数绑定逻辑,运行时只会从Mapper方法入参、@Param标注的参数值中查找匹配项,根本不会读取全局变量里存的内容,自然会取不到值。
你原来编写的configuration.getVariables().put("secretKey", "my secret key")这段配置逻辑本身没有问题,只是和SQL里的取值语法不匹配。
可落地的实现方案
方案1:适配全局变量的语法要求
如果不想调整Java侧的拦截器、Mapper方法定义,只需要把SQL里对应位置的#{secretKey}改成${secretKey}即可,改完的SQL示例如下:
select a.ID, CAST(AES_DECRYPT(a.FIRST_NAME, SHA2(${secretKey}, 512)) AS CHAR) FIRST_NAME, CAST(AES_DECRYPT(a.LAST_NAME, SHA2(${secretKey}, 512)) AS CHAR) LAST_NAME, USERNAME, PASSWD, b.ID ID_ROLE, b.NAME ROLE_NAME from users a join roles b on a.ID_ROLE = b.ID where USERNAME = #{username,jdbcType=VARCHAR}
这个方案的注意事项:
- 因为
${}是直接把变量值拼到SQL文本里,你这里的secretKey是服务端自定义的固定配置值,并非外部用户传入的内容,不存在SQL注入风险 - 这种方式的局限是全局变量在应用启动时就会加载到MyBatis配置里,如果后续修改secretKey值需要重启应用才能生效
方案2:通过MyBatis拦截器统一注入预编译参数(推荐)
如果不想用文本拼接的${}语法,希望走#{}的预编译参数绑定逻辑,可以自定义MyBatis参数拦截器,统一为所有目标表的select查询注入secretKey参数,完全不用修改每个Mapper方法的入参定义。
实现逻辑要点:
- 拦截器匹配所有涉及目标加密表的select查询操作
- 从Spring配置上下文读取实时的secretKey值,动态注入到当前查询的参数Map中
- 让SQL里原有的
#{secretKey}能正常从参数上下文匹配到值,完成预编译参数绑定
这个方案的优势是可以保留预编译的类型安全特性,同时支持从配置中心读取动态secretKey、无需重启就可以更新值,最适配你“为某张表的所有select查询统一传默认解密参数”的需求。
常见避坑点
- 不要混淆
#{}和${}的取值范围:#{}是运行时参数绑定,只匹配Mapper入参、拦截器动态注入的参数;${}是静态文本替换,可匹配全局配置变量、SQL片段引用 - 不要把全局变量的值设置成外部可传入的内容,避免触发SQL注入风险
内容的提问来源于stack exchange,提问作者HK15
相关产品推荐
相关产品推荐

