单个参数:
#{ 参数名 } :取出参数值
单个参数的情况下,mybatis不会做特殊处理,括号里面写啥都可以。
举例:
此处传入的是id,但是在sql语句中,将参数名修改成其他东西,该sql语句也是可行的。
多个参数:
mybatis会做特殊处理,多个参数会被封装成一个map,#{ } 就是从map中获取指定的key的值。
key:param1...paramN 或者 参数的索引0,1...N-1
value:传入的参数值
所以应该改成如下就可以正常运行:
但是这样子并不好用,那么推荐方法使用命名参数。
命名参数:
明确指定封装参数时map的key。
添加@Param注解,来明确指定key值。
举例:
多个参数被封装成一个map,
key:使用@Param注解指定的值
value:传入的参数值
#{ 指定的key }:取出对应的参数值
此时,再用原先的方法编写的话,运行是没有任何问题了的:
pojo:
如果多个参数正好是业务逻辑中的数据模型,可以直接传入pojo就行了。
#{ 属性名 }:取出传入的pojo的属性值
map:
如果多个参数不是业务逻辑中的数据,没有对应的pojo,不经常使用的话,为了方便,可以传入map
#{ key }:取出map中对应的值
举例:
javabean
测试类
sql映射文件(resultType不能忘记写)
TO:
如果多个参数不是业务模型中的数据,但是经常要使用,推荐编写一个TO(Transfer Object)数据传输对象
比如查询分页的时候:
Page{
int index;
int size;
}
不同场景的应用
场景一:
场景二:
场景三:
特别注意:
如果是Collection(List、Set)类型或者是数组,mybatis也会做特殊处理。同样把传入的list或者数据封装在map中。
key:如果是Collection(collection),如果是List(list),如果是数组(array)
所以在场景三中,以下写法都是不对的:
结合源码理解mybatis处理参数的过程
总结:
参数多时会封装map,为了不混乱,可以使用@Param来指定封装时使用的key;#{ key }就可以取出map中的值
(@Param("id")Integer id,@Param("lastName")String lastName);
ParamNameResolver解析参数封装map的;
其中,names:{ 0=id,1=lastName } 构造器的就确定好了
确定流程:
1、获取每个标了param注解的参数的@Param的值:id,lastName;赋值给name;
2、每次解析一个参数给map中保存信息:(key:参数索引,value:name的值)
name的值:
标注了param注解:注解的值
若没有param标注:1、全局配置:useActualParamName(jdk1.8):name=参数名
2、name=map.size( ); 相当于当前元素的索引
#{ }:可以获取map中的值或者pojo对象属性的值;
${ }:可以获取map中的值或者pojo对象属性的值;
两者区别:
#{ }:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
${ }:取出的值直接拼装在sql语句中;会有安全问题;
大多情况下,取参数的值都应该去使用#{ }
在什么情况下使用${ }:原生jdbc不支持占位符的地方就可以使用${ }进行取值。
比如分表、排序等;按照年份分表拆分
select * from ${year}_salary where xxx
select * from tbl_employee order by ${f_name} ${order}
当然,绑定了@Param注解的参数值,只能用#{ }
#{ }更丰富的用法
规定参数的一些规则:
参数位置支持的属性:javaType、jdbcType、mode(用于储存过程)、numberScale(保留几位小数)、resultMap(封装的结果类型)、typeHandler(处理数据的类型处理器)、jdbcTypeName(跟jdbcType一样)、expression(未来准备支持的功能)
jdbcType:通常需要在某种特定的条件下被设置。在数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。
比如:Oracle(报错)。此时,就要告诉mybatis这个jdbcType是什么类型。
在Oracle情况下,正常添加的情况:
把email参数置空就会出错了,无效的类型,意思是Oracle不能识别null值的类型
但如果换做mysql做测试,则是没有任何问题的。
解析原因:
JdbcType Other: 无效的类型。
因为mybatis对所有的null都映射的是原生的Jdbc的Other类型,Oracle不能正确处理,而mysql兼容这些东西。
全局配置中:jdbcTypeForNull=OTHER;oracle不支持;
两种解决方案:
1、#{ email,jdbcType=OTHER }
在相应字段里修改
2、jdbcTypeForNull=NULL
在全局设置中修改
在jdbcType这个枚举类下,本来为空会对应sql包下OTHER ,现在则会对应成NULL