在映射器中select元素代表SQL的select语句,用于查询。在SQL中,select语句是用的最多的语句,在MyBatis中select元素也是用的最多的元素,使用的多就意味着强大和复杂。先来看看select的配置:
1、简单的select元素应用
我们先来看一个简单的例子:统计用户表中同一个姓氏的用户数量。代码如下:
<select id="countUserByFirstName" parameterType="string" resultType="int">
select count(*) total from user
where user_name like concat(#{firstName},'%')
<select>
只是这条SQL还不够,我们还需要一个接口方法程序才能运行起来,比如SQL可以这样定义接口方法:
public Integer countUserByFirstName(String firstName);
2、自动映射和驼峰映射
MyBatis提供了自动映射功能,使用自动映射的好处在于能有效减少大量的映射配置,从而减少工作量。我们将以角色表(字段有 id,roleName,note)为例。
在setting元素中有两个可以配置的选项autoMappingBehavior和mapUnderscoreToCamelCase,他们是控制自动映射和驼峰映射的开关。
配置自动映射的autoMappingBehavior选项的取值范围是:
在默认情况下,我们一般使用默认的PARTIAL。为了实现自动映射,首先要给出一个POJO——Relo,代码如下:
package pojo;
public class Role {
private Long id;
private String roleName;
private String note;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
这是一个十分简单的POJO。如果编写的SQL列名和属性名保持一致,那么他就会形成自动映射,比如通过id获取角色的信息。
<select id="getRole" parameterType="long" resultType="role">
select id,role_name as roleName,note from t_role where id=#{id}
</select>
原来的列名role_name被别名roleName代替了,这样就和POJO上的属性名称保持一致了。此时MyBatis就会将这个结果集映射到POJO的属性roleName上,自动完成映射,就无须在进行任何配置,明显减少了工作量。
3、传递多个参数
在现实需求中可以有多个参数,比如订单可以有订单号查询,也可以根据订单名称、日期等参数进行查询,为此要研究一下多个参数的场景。假设要通过角色名称(role_name)和备注(note)对角色进行模糊查询,这样就有2个参数了。
(1)、使用map接口传递参数
在MyBatis中运行map接口通过键值对传递多个参数,把接口方法定义为:
public List<Role> findRolesByMap(Map<String,Object>parameterMap);
此时,传递给映射器的是一个map对象,使用它在SQL中设置对应的参数,代码如下:
<select id="findRolesByMap" parameterType="map" resultType="role">
select id,role_name as roleName,note from role
where role_name like concat('%',#{roleName},'%')
and note like concat('%',#{note},'%')
</select>
注意,参数roleName和note,要求的也是map的键,也就是需要如下代码传递参数:
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Map<String,Object> parameterMap = new HashMap<String,Object>();
parameterMap.put("roleName","1");
parameterMap.put("note","1");
List<Role> roles=roleMapper.findRolesByMap(parameterMap);
在SQL中的参数标识将会被这里设置的参数所取代,这样就能运行了。严格来说,map几乎适用于所有场景,但是我们用的不多,原因有两个:1、map是一个键值对应的集合,使用者要通过阅读它的键,才能明白其作用;2、map不能限定其传递参数的数值类型,因此业务能力不强,可读性差。
(2)、使用注解传递参数
MyBatis可以通过注解@param去定义映射器的参数名称,使用它可以得到更好的可读性,把接口方法定义为:
public List<Role> findRolesByAnnotation(@Param("roleName")String rolename,
@Param("note")String note);
此时代码的可读性大大提升了,使用者能明确参数roleName是角色名称,而note是备注,一目了然,这时候的映射文件代码如下:
<select id="findRolesByAnnotation" resultType="role">
select id,role_name as roleName,note from role
where role_name like concat('%',#{roleName},'%')
and note like concat('%',#{note},'%')
</select>
(3)、通过JavaBean传递多个参数
先定义一个参数的POJO——RoleParams,代码如下:
public class RoleParams {
private String roleName;
private String note;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
此时把接口方法定义为:
public List<Role> findRolesByBean(@Param(RoleParams roleParam);
JavaBean的属性roleName代表角色名称,而note代表备注,然后修改映射文件:
<select id="findRolesByBean" parameterType="pojo.RoleParams" resultType="role">
select id,role_name as roleName,note from role
where role_name like concat('%',#{roleName},'%')
and note like concat('%',#{note},'%')
</select>
引入JavaBean定义的属性作为参数,然后查询。
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
RoleParams roleParams = new RoleParams();
roleParams.setRoleName("1");
roleParams.setNote("1");
List<Role> roles=roleMapper.findRolesByBean(roleParams);
(4)、混合使用
在某些情况下需要混合使用几种方法传递参数。举个例子,查询一个角色,可以通过角色名称和备注进行查询,与此同时还需要支持分页,而分页的POJO实现代码如下:
public class PageParams{
private int start;
private int limit;
}
这个时候接口设计就得如下所示了:
public List<Role> findRolesByMix(@Param("params") RoleParams roleParams,
@Param("page") PageParams pageParams);
这样设置之后,映射文件也要做出相应的改变:
<select id="findRolesByMix" resultType="role">
select id,role_name as roleName,note from role
where role_name like concat('%',#{params.roleName},'%')
and note like concat('%',#{params.note},'%')
limit #{page.start},#{page.limit}
</select>
总结
4、使用resultMap映射结果集
自动映射和驼峰映射规则比较简单,无法定义多的属性,比如typeHandler、级联等。为了支持复杂的映射,select元素提供了resultMap属性。先定义resultMap属性,代码如下:
<mapper namespace="mapper.RoleMapper">
<resultMap id="rolemap" type="role>
<id property="id" column="id"/>
<result property="roleName" column="role_name" />
<result property="note" column="note" />
</resultMap>
<select id="getRoleUseResultMap" parameterType="long" resultType="roleMap">
select id,role_name,note from role
where id=#{id}
</select>
</mapper>
解释一下这段代码的含义:
5、分页参数RowBounds
MyBatis不仅支持分页,它还内置了一个专门处理分页的类——RowBounds。
RowBounds源码如下所示:
package other;
public class RowBounds {
public static final int NO_ROW_OFFSET=0;
public static final int NO_ROW_LIMIT=Integer.MAX_VALUE;
public static final RowBounds DEFAULT=new RowBounds();
private int offset;
private int limit;
public RowBounds(){
this.offset=NO_ROW_OFFSET;
this.limit=NO_ROW_LIMIT;
}
public RowBounds(int offset,int limit){
this.offset=offset;
this.limit=limit;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
}
offset属性是偏移量,即从第几行开始读取记录。limit是限制条数,从源码可知,默认值为0和java最大整数(2147483647),使用它十分的简单,只要给接口增加一个RowBounds参数即可。
public List<Role> findRolesByRowBounds(@Param("roleName")String rolename,
@Param("note")String note,
RowBounds rowBounds);
对于SQL而言,映射内容如下:
<select id="findRolesByRowBounds" resultType="role">
select id,role_name as roleName,note from role
where role_name like concat('%',#{roleName},'%')
and note like concat('%',#{note},'%')
</select>
注意,映射文件中没有任何关于RowBounds参数的信息,它是MyBatis的一个附加参数,MyBatis会自动识别它,据此进行分页。