MyBatis中使用#{}和${}占位符传递参数的各种报错信息处理

在Mapper层使@Select注解进行SQL语句查询时,往往需要进行参数传入和拼接,一般情况下使用两种占位符#{参数名}和${参数名},两者的区别为:

一、两种占位符的区别

1、参数传入方式的区别

#{}是预编译处理,后台输出的日志会将SQL语句中的#{}占位符输出为?,将传入的Parameter传入SQL语句。

{}是字符串硬替换,会直接将传入的参数直接替换{}占位符,不进行预处理。有SQL注入的风险。

2、参数传入后处理的区别

#{}传入参数后,会自动给参数加上' '(引号),例如:

复制代码
@Select("select name from user where id = #{id}")
String queryNameById(String id);

在传入id为1001之后,输出的sql为:

复制代码
select name from user where id ='1001'

**${}传入的参数会硬替换字符串,不会有其他处理,**例如:

复制代码
@Select("select name from user where id = ${id}")
String queryNameById(String id);

在传入id为1001后输出的sql是:

复制代码
select name from user where id = 1001

参数会直接替换${}而不进行其他处理,如果这里你需要给参数加上' ',则需要这么修改代码:

复制代码
@Select("select name from user where id = '${id}'")
String queryNameById(String id);

这样进行替换后的sql就会变为参数加引号的sql语句。

二、常见报错处理

1、索引超出范围

复制代码
详细报错为:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='name', mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: com.microsoft.sqlserver.jdbc.SQLServerException: 索引 1 超出范围。] with root cause

日志信息报错索引超出范围,可能是因为语句拼接后出现语法错误,往往造成该错误的是对语句中占位符处的引号处理问题。例如:

复制代码
@Select("select  kunnr,name1 from openquery(hana2,'select top 10 * from SAPHANADB.kna1 where name1 like ''%${name}%'' and name1 not like ''冻结''')")
List<Biz> queryBizListByName(String name);

如果这里使用#{}进行占位符,那么组成的sql会变成 like ''%'name'%'' and,参数会多一个' '进行包裹,语法就会出错。所以不管是使用concat进行拼接,还是直接进行替换,使用两种占位符时都要根据其使用特点,注意包裹的' ',来达到符合自己SQL语法的使用。在出现"索引超出范围"的报错时,可以通过检查自己sql的语法是否出错,来看看是否可以解决问题。

2、"@P0"附近有语法错误

复制代码
详细报错为:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: com.microsoft.sqlserver.jdbc.SQLServerException: "@P0"附近有语法错误。

日志报这个错误,可能是由于你的sql语句中,使用了不支持#{}占位符的函数,例如Top和Order By等函数,是不支持使用#{}占位符的,可以将#{}改为{},使用字符串替换可以解决问题。但要注意#{}改为{}时引号包裹引起的语法问题。

提醒:代码中尽量使用#{}占位符,尽量避免使用${}占位符,因为#{}会更加安全。

相关推荐
每天都要加油呀!21 分钟前
多租户中间件适配
java·多租户
014-code1 小时前
Java 并发中的原子类
java·开发语言·并发
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题】【Java基础篇】第29题:静态代理和动态代理的区别是什么
java·开发语言·后端·面试·代理模式
善恶怪客1 小时前
Java-数组和可变参数
java·开发语言
小编码上说1 小时前
LSH(局部敏感哈希)分桶,海量数据下的相似性搜索解决方案
java·spring boot·缓存·langchain4j·lsh·局部敏感哈希·ai调用优化
计算机_毕业设计1 小时前
java-springboot数字藏品系统 基于 SpringBoot 的区块链数字艺术品交易平台 Java 微服务架构下的加密藏品展示与拍卖系统计算机毕业设计
java·spring boot·课程设计
ONVO ncen1 小时前
Redis6.2.6下载和安装
java
丑八怪大丑1 小时前
JDK8-17新特性
java·开发语言
京师20万禁军教头1 小时前
37面向对象(高级)-main方法
java
书源丶1 小时前
三十五、Java 泛型——类型安全的「万能模板」
java·开发语言·安全