MyBatis基于XML的详细使用-参数、返回结果 处理

3,854 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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如下:
修改前:

image.png

修改后:

image.png

这样在使用复杂语句的时候,我们调试就比较方便了,不用自己挨个去匹配参数值。

二、select的参数传递

2-1、单个参数传递

如:SelectEmp(Integer id);mybatis 不会做任何特殊要求
获取方式: #:{输入任何字符获取参数}

image.png 如上:虽然我们传递的是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获取参数 image.png

使用param获取参数

image.png

获取方式
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}

通过使用别名的方式获取参数 image.png

如果使用@Param的方式也可以使用param来获取参数 image.png

在实际项目中建议使用通过@Param来设置参数别名,这样在获参数的时候就比较清晰了,方便后期的维护。

需要注意的是,如果通过@Param设置别名,就不能使用arg来获取参数了。

2-3、javaBean的参数

2-3-1、使用一个javaBean传参

单个参数:Emp SelectEmp(Emp emp);
获取方式:可以直接使用属性名
emp.id=====>#{id}
emp.name=====>#{name}\

image.png 如上图通过传递一个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后面跟上属性名称即可

image.png

在设置了@Param的情况下,就可以更加设置的别名来获取了 image.png

即使在设置了@Param的情况下,依然可以通过param来获取参数值,入下: image.png

2-4、集合或者数组参数

2-4-1、集合传递参数

Emp SelectEmp(List< String> name);

如果是list,MyBatis会自动封装为map:
{key:"list":value:name}
没用@Param("")要获得

name.get(0) =====> #{list[0]} image.png

name.get(0) =====> #{agr0[0]} image.png

有@Param("names")要获得

names.get(0) =====> #{names[0]} image.png

names.get(0) =====> #{param1[0]} image.png

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即可 image.png

如果是基础数据类型或者包装数据类型直接指定别名就行了

image.png

四、自定义结果集

可以使用ResultMap自定义结果集,需要将数据库字段和pojo的字段属性进行一一对应,这样就可以方便我们把数据库字段的蛇形命名指向到pojo中属性的驼峰命名上,比如:create_time-->createTime.

4-1、为何使用自定义结果集

image.png 如上图,数据库字段为create_time,pojo中的字段为createTime,这样再通过sql查询的时候就无法将查出的时间对应到pojo的属性上了,当然也可以通过sql 的as 设置别名来处理如下:

image.png

这样一般为比较小的系统使用,但是如果这个Mapper.xml中的sql量比较多,并且用create_time的sql也很多,就得每条都进行设置了,这样不仅增加了一些工作流,在以后的维护中也带来了比较多的影响。

因此我们就可以使用resultMap来进行映射处理了

image.png

4-2、自定义结果集的注意事项

声明resultMap自定义结果集 resultType 和 resultMap 只能使用一个。
id 唯一标识, 需要和<select 上的resultMap 进行对应
type 需要映射的pojo对象, 可以设置别名
autoMapping 自动映射,(默认=true) 只要字段名和属性名遵循映射规则就可以自动映射,但是不建议,哪怕属性名和字段名一一对应上了也要显示的配置映射 如下在设置false,并且将对映射关系注释的情况下,就无法进行自动映射了

image.png 在设置为true的情况下,即使注释的字段名和属性名一直的映射关系,也可以进行自定映射

image.png

extends 如果多个resultMap有重复映射,可以声明父resultMap,将公共的映射提取出来, 可以减少子resultMap的映射冗余

image.png 如上图可以看到,把返回的id映射注释掉,并且设置不自动映射,但是使用了extends,继承了common_map这样就相当于拥有了其下面的映射。

另外如果数据库字段和pojo属性可以对应上,那么Mapper.xml中的映射是可以省略的,但是不建议,这样对于后面代码的可读性会有一些影响。

需要注意的是,虽然上面我们对于主键id同样使用了 可以完成映射,但是实际上应该使用id的方式来设置主键(对底层存储有性能作用)

<id column="id" property="id"/>

五、select查询相关属性

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。
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。
resultSetTypeFORWARD_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(使用存储过程使用,使用频率也不高)