返回介绍

4.2 select 元素

发布于 2025-04-26 13:08:33 字数 8285 浏览 0 评论 0 收藏

4.2.1 概述

毫无疑问,select 元素是我们最常用也是功能最强大的 SQL 语言。select 元素帮助我们从数据库中读出数据,组装数据给业务人员。执行 select 语句前,我们需要定义参数,它可以是一个简单的参数类型,例如 int、float、String,也可以是一个复杂的参数类型,例如 JavaBean、Map 等,这些都是 MyBatis 接受的参数类型。执行 SQL 后,MyBatis 也提供了强大的映射规则,甚至是自动映射来帮助我们把返回的结果集绑定到 JavaBean 中。select 元素的配置如表 4-2 所示。

表 4-2 select 元素的配置

084-2 085-1

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 描述

字 段类 型说 明
IDINT(20)角色编号,主键,递增
ROLE_NAMEVARCHAR(60)角色名称
NOTEVARCHAR(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。