4.2 select 元素
4.2.1 概述
毫无疑问,select 元素是我们最常用也是功能最强大的 SQL 语言。select 元素帮助我们从数据库中读出数据,组装数据给业务人员。执行 select 语句前,我们需要定义参数,它可以是一个简单的参数类型,例如 int、float、String,也可以是一个复杂的参数类型,例如 JavaBean、Map 等,这些都是 MyBatis 接受的参数类型。执行 SQL 后,MyBatis 也提供了强大的映射规则,甚至是自动映射来帮助我们把返回的结果集绑定到 JavaBean 中。select 元素的配置如表 4-2 所示。
表 4-2 select 元素的配置
4.2.2 简易数据类型的例子
例如,我们需要统计一个姓氏的用户数量。我们应该把姓氏作为参数传递,而将结果设置为整形返回给调用者,如代码清单 4-1 所示。
代码清单 4-1:select 的简单例子
<select id="countFirstName" parameterType="string" resultType="int"> select count(*) as total from t_user where name like concat(#{firstName}, ‘%’) </select>
我们在接口 UserDao 中定义方法。
public int countFirstName(String firstName);
这样就可以使用 MyBatis 调用 SQL 了,十分简单。下面对操作步骤进行归纳概括。
id 标出了这条 SQL。
parameterType 定义参数类型。
resultType 定义返回值类型。
当然这个例子只是为了用来入门,我们将来遇到的问题远比这个复杂得多。
4.2.3 自动映射
有这样的一个参数 autoMappingBehavior,当它不设置为 NONE 的时候,MyBatis 会提供自动映射的功能,只要返回的 SQL 列名和 JavaBean 的属性一致,MyBatis 就会帮助我们回填这些字段而无需任何配置,它可以在很大程度上简化我们的配置工作。在实际的情况中,大部分的数据库规范都是要求每个单词用下划线分隔,而 Java 则是用驼峰命名法来命名,于是使用列的别名就可以使得 MyBatis 自动映射,或者直接在配置文件中开启驼峰命名方式。
让我们来看一个例子,体验一下自动映射的好处。我们需要通过角色编号查询一个角色,并将结果集映射到角色的 JavaBean 上。我们先给出 JavaBean,如代码清单 4-2 所示。
代码清单 4-2:Role.java
package com.learn.chapter4.po; 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; } }
而数据库表(T_ROLE)的字段如表 4-3 所示。
表 4-3 数据库表 T_ROLE 描述
字 段 | 类 型 | 说 明 |
ID | INT(20) | 角色编号,主键,递增 |
ROLE_NAME | VARCHAR(60) | 角色名称 |
NOTE | VARCHAR(1024) | 备注 |
让我们编写 Mapper 的映射语句,如代码清单 4-3 所示。
代码清单 4-3:自动映射
<select parameterType="id" id="getRole" resultType="com.learn. chapter4. pojo.Role" > Select id, role_name as roleName, note from t_role where id =#{id} </select>
对于 RoleDao 接口,我们提供一个方法。
public Role getRole(Long id);
这样就可以使用它,角色名称(role_name)使用 SQL 提供的别名功能使得查询结果和 JavaBean 的属性一一对应起来,然后 MyBatis 提供的自动映射的功能使得我们无需过多的提供配置信息,大大减少了我们的工作量。
自动映射可以在 settings 元素中配置 autoMappingBehavior 属性值来设置其策略。它包含 3 个值。
NONE,取消自动映射。
PARTIAL,只会自动映射,没有定义嵌套结果集映射的结果集。
FULL,会自动映射任意复杂的结果集(无论是否嵌套)。
默认值为 PARTIAL。所以在默认的情况下,它可以做到当前对象的映射,使用 FULL 是嵌套映射,在性能上会下降。
如果你的数据库是规范命名的,即每一个单词都用下划线分隔,POJO 采用驼峰式命名方法,那么你也可以设置 mapUnderscoreToCamelCase 为 true,这样就可以实现从数据库到 POJO 的自动映射了。
4.2.4 传递多个参数
4.2.3 节的例子是传递一个参数给映射器,更多的时候我们需要传递多个参数给映射器。现在我们要根据角色名称和备注来模糊查询角色,显然这涉及到了两个参数。
4.2.4.1 使用 Map 传递参数
我们可以使用 MyBatis 提供的 Map 接口作为参数来实现它,如代码清单 4-4 所示。
代码清单 4-4:使用 Map 传递参数
<select id="findRoleByMap" parameterType="map" resultMap="roleMap"> select id, role_name, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%') </select>
对于 RoleDao 接口,我们提供一个方法。
public List<Role> findRoleByMap(Map<String, String> params);
输入上面的代码就可以使用这个方法了,如代码清单 4-5 所示。
代码清单 4-5:传递参数
Map<String, String >paramsMap = new HashMap<String, String>(); paramsMap.put("roleName", "me"); paramsMap.put("note", "te"); roleMapper.findRoleByMap(paramsMap);
这个方法虽然简单易用,但是有一个弊端:这样设置的参数使用了 Map,而 Map 需要键值对应,由于业务关联性不强,你需要深入到程序中看代码,造成可读性下降。MyBatis 为我们提供了更好的实现方法,它就是注解参数的形式,让我们看看如何实现。
4.2.4.2 使用注解方式传递参数
我们需要使用 MyBatis 的参数注解 @Param(org.apache.ibatis.annotations.Param)来实现想要的功能。操作方法是,把 RoleDao 接口修改为下面的形式。
public List<Role> findRoleByAnnotation(@Param("roleName") String rolename, @Param("note") String note);
我们把映射器的 XML 修改为无需定义参数类型,如代码清单 4-6 所示。
代码清单 4-6:注解式参数
<select id="findRoleByAnnotation" resultMap="roleMap"> select id, role_name, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%') </select>
当我们把参数传递给后台的时候,通过 @Param 提供的名称 MyBatis 就会知道#{roleName}代表 rolename 参数,参数的可读性大大提高了。但是这会引起另一个麻烦,一条 SQL 拥有 10 个参数的查询,如果我们都使用 @Param 方式,那么参数将十分复杂,可读性依旧不高,不过 MyBatis 为我们提供了 JavaBean 定义参数的方式来解决这个问题。
4.2.4.3 使用 JavaBean 传递参数
在参数过多的情况下,MyBatis 允许组织一个 JavaBean,通过简单的 setter 和 getter 方法设置参数,这样就可以提高我们的可读性。首先,定义一个 RoleParams 的 JavaBean,如代码清单 4-7 所示。
代码清单 4-7:定义简易的参数 JavaBean
package com.learn.chapter4.params; public class RoleParam { 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; } }
我们用 JaveBean 改写一下传递参数的例子,如代码清单 4-8 所示。
代码清单 4-8:使用 JavaBean 传递参数
<select id="findRoleByParms" parameterType="com.learn.chapter4. params.RoleParam" resultMap="roleMap"> select id, role_name, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%') </select>
同样我们在 RoleDao 接口提供一个方法。
public List<Role> findRoleByParams(RoleParam params);
这就是通过 JavaBean 的方式传递多个参数的方式。
4.2.4.4 总结
从 4.2.4.1 节到 4.2.4.3 节我们描述了 3 种传递多个参数的方式,下面对各种方式加以点评和总结,以利于我们在实际操作中的应用。
使用 Map 传递参数。因为 Map 导致业务可读性的丧失,从而导致后续扩展和维护的困难,我们应该在实际的应用中果断废弃这样的传递参数的方式。
使用 @Param 注解传递多个参数,这种方式的使用受到参数个数(n)的影响。当 n≤5 时,它是最佳的传参方式,它比用 JavaBean 更好,因为它更加直观;当 n>5 时,多个参数将给调用带来困难。
当参数个数多于 5 个时,建议使用 JavaBean 方式。
4.2.5 使用 resultMap 映射结果集
我们在 4.2.3 节讲解了自动映射,但是在某些时候,我们需要处理更为复杂的映射,resultMap 为我们提供了这样的模式。我们需要在映射器中定义 resultMap,这也是我们常见的场景,如代码清单 4-9 所示。
代码清单 4-9:使用 resultMap 作为结果集
<resultMap id="roleResultMap" type="com.learn.chapter4.pojo.Role"> <id property="id" column="id" /> <result property="roleName" column="role_name"/> <result property="note" column="note"/> </resultMap> ...... <select parameterType="long" id="getRole" resultMap = "roleResultMap" > select id, role_name, note from t_role where id = #{id} </select>
解释一下 resultMap 的配置。
定义了一个唯一标识(id)为 roleResultMap 的 resultMap,用 type 属性去定义它对应的是哪个 JavaBean(也可以使用别名)。
通过 id 元素定义 resultResultMap,这个对象代表着使用哪个属性作为其主键。result 元素定义普通列的映射关系,例如,把 SQL 结果返回的列 role_no 和 type 属性定义 JavaBean 的属性 roleNo 等做一一对应。
这样 select 语句就不再需要使用自动映射的规则,直接用 resultMap 属性指定 roleResultMap 即可,这样 MyBatis 就会使用我们的自定义映射规则。
resultMap 可没有你所看见的那么简单,它是映射器中最为复杂的元素,它一般用于复杂、级联这些关联的配置。在简单的情况下,我们可以使用 resultType 通过自动映射来完成,这样配置的工作量就会大大减少,未来随着进一步的学习深入,我们还会讨论 resultMap 的高级应用。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论