一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
一、参数的获取方式
在xml文件中编写sql语句的时候有两种取值的方式,分别是#{}和${}。
1-1、#{} 传值
使用#{}传值相当于jdbc中的
String sql=" SELECT id,user_name FROM EMP WHERE id=?"
这样就会经过JDBC当中PreparedStatement的预编译,会根据不同的数据类型来编译成对应数据库所对应的数据。从而能够有效的防止SQL注入。 推荐使用!!
1-1-1、#{}的特殊用法
自带很多内置参数的属性:通常不会使用。了解
javaType、jdbcType、mode、numericScale、resultMap、typeHandler.
比如 需要改变默认的NULL===>OTHER:#{id,javaType=NULL}
想保留小数点后两位:#{id,numericScale=2}
1-2、 ${}传值
使用#{}传值相当于jdbc中的
String sql=" SELECT id,user_name FROM EMP WHERE id="+id
这样就不会进行预编译,会直接将输入进来的数据拼接在SQL中。存在SQL注入的风险。不推荐使用。
1-2-1、${}的特殊用法
1.调试情况下可以临时使用。
2.实现一些特殊功能:前提一定要保证数据的安全性。
比如:动态表、动态列. 动态SQL.
比如我们把EmpMapper.xml中的#{}改为${}查看执行sql如下:
修改前:
修改后:
这样在使用复杂语句的时候,我们调试就比较方便了,不用自己挨个去匹配参数值。
二、select的参数传递
2-1、单个参数传递
如:SelectEmp(Integer id);mybatis 不会做任何特殊要求
获取方式: #:{输入任何字符获取参数}
如上:虽然我们传递的是ID,但是接收参数的时候可以随便写,不做特殊限制。
2-2、多个参数传递
2-2-1、使用arg或者param获取参数
Emp SelectEmp(Integer id,String name);
mybatis 会进行封装,会将传进来的参数封装成map:
1个值就会对应2个map项 :
id===> {key:arg0 ,value:id的值},{key:param1 ,value:id的值}
name===> {key:arg1 ,value:id的值},{key:param2 ,value:id的值}
如下使用arg获取参数
使用param获取参数
获取方式:
id=====> #{arg0} 或者 #{param1}
name=====> #{arg1} 或者 #{param2}\
总结:使用arg从0开始,param从1开始
2-2-2、使用@Param注解设置参数
除了使用这种方式还有别的方式,因为这种方式参数名没有意义:
设置参数的别名:@Param(""):
SelectEmp(@Param("id") Integer id,@Param("name") String name);\
当使用了@Param:
id=====> #{id} 或者 #{param1}
name=====> #{name} 或者 #{param2}
通过使用别名的方式获取参数
如果使用@Param的方式也可以使用param来获取参数
在实际项目中建议使用通过@Param来设置参数别名,这样在获参数的时候就比较清晰了,方便后期的维护。
需要注意的是,如果通过@Param设置别名,就不能使用arg来获取参数了。
2-3、javaBean的参数
2-3-1、使用一个javaBean传参
单个参数:Emp SelectEmp(Emp emp);
获取方式:可以直接使用属性名
emp.id=====>#{id}
emp.name=====>#{name}\
如上图通过传递一个javaBean,在使用的时候只能输入属性名来获取参数值。
2-3-2、多个参数
多个参数:Emp SelectEmp(Integer num,Emp emp);\
获得非javaBean就可以通过如下方式获取 num===> #{param1} 或者 @Param\
获得javaBean对象的参数可以通过如下方式获取
emp===> 必须加上对象别名:
emp.id===> #{param2.id} 或者 @Param("emp")Emp emp ====>#{emp.id}
emp.name===> #{param2.name} 或者 @Param("emp")Emp emp ====>#{emp.name}
如下在未设置@Param的情况下,只能通过param来获取参数,javaBean对象的在param后面跟上属性名称即可
在设置了@Param的情况下,就可以更加设置的别名来获取了
即使在设置了@Param的情况下,依然可以通过param来获取参数值,入下:
2-4、集合或者数组参数
2-4-1、集合传递参数
Emp SelectEmp(List< String> name);
如果是list,MyBatis会自动封装为map:
{key:"list":value:name}
没用@Param("")要获得
name.get(0) =====> #{list[0]}
name.get(0) =====> #{agr0[0]}
有@Param("names")要获得
names.get(0) =====> #{names[0]}
names.get(0) =====> #{param1[0]}
2-4-2、数组传递参数
如果是数组,MyBatis会自动封装为map:
{key:"array":value:name}
没用@Param("")要获得
name.get(0) =====> #{array[0]}
name.get(0) =====> #{agr0[0]}
有@Param("name")要获得:
name.get(0) =====> #{name[0]}
name.get(0) =====> #{param1[0]}
2-5、map方式传参
和javaBean的参数传递是一样,一般情况下:
请求进来的参数 和pojo对应,就用pojo
请求进来的参数 没有和pojo对应,就用map
请求进来的参数 没有和pojo对应上,但是使用频率很高,就用TO、DTO(就是单独为这些参数创建一个对应的javaBean出来,使参数传递更规范、更重用)
三、处理集合返回结果
返回结果类型:
如果返回一行数据,就可以使用pojo接收,或者map
如果返回多行数据,就可以使用List< pojo>或者List< map>然后resultType指定List中的泛型就可以了
如下,虽然返回数据类型为List< Emp> 但是在EmpMapper.xml中的resultType指定为Emp即可
如果是基础数据类型或者包装数据类型直接指定别名就行了
四、自定义结果集
可以使用ResultMap自定义结果集,需要将数据库字段和pojo的字段属性进行一一对应,这样就可以方便我们把数据库字段的蛇形命名指向到pojo中属性的驼峰命名上,比如:create_time-->createTime.
4-1、为何使用自定义结果集
如上图,数据库字段为create_time,pojo中的字段为createTime,这样再通过sql查询的时候就无法将查出的时间对应到pojo的属性上了,当然也可以通过sql 的as 设置别名来处理如下:
这样一般为比较小的系统使用,但是如果这个Mapper.xml中的sql量比较多,并且用create_time的sql也很多,就得每条都进行设置了,这样不仅增加了一些工作流,在以后的维护中也带来了比较多的影响。
因此我们就可以使用resultMap来进行映射处理了
4-2、自定义结果集的注意事项
声明resultMap自定义结果集 resultType 和 resultMap 只能使用一个。
id 唯一标识, 需要和<select 上的resultMap 进行对应
type 需要映射的pojo对象, 可以设置别名
autoMapping 自动映射,(默认=true) 只要字段名和属性名遵循映射规则就可以自动映射,但是不建议,哪怕属性名和字段名一一对应上了也要显示的配置映射
如下在设置false,并且将对映射关系注释的情况下,就无法进行自动映射了
在设置为true的情况下,即使注释的字段名和属性名一直的映射关系,也可以进行自定映射
extends 如果多个resultMap有重复映射,可以声明父resultMap,将公共的映射提取出来, 可以减少子resultMap的映射冗余
如上图可以看到,把返回的id映射注释掉,并且设置不自动映射,但是使用了extends,继承了common_map这样就相当于拥有了其下面的映射。
另外如果数据库字段和pojo属性可以对应上,那么Mapper.xml中的映射是可以省略的,但是不建议,这样对于后面代码的可读性会有一些影响。
需要注意的是,虽然上面我们对于主键id同样使用了 可以完成映射,但是实际上应该使用id的方式来设置主键(对底层存储有性能作用)
<id column="id" property="id"/>
五、select查询相关属性
| 属性 | 描述 |
|---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
resultType | 期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。 |
resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
fetchSize | 这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。 |
statementType | 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
resultOrdered | 这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false。 |
resultSets | 这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 |
以上部分,经常使用的有:id、parameterType、resultType、resultMap、flushCache、useCache、statementType(使用存储过程使用,使用频率也不高)