Java / MyBatis select

MyBatis select

1. 前言

本小节,我们将一起学习 MyBatis select。

在 MyBatis 中,select 标签对应于 SQL 语句中的 select 查询,我们会在 select 标签中填充 SQL 查询语句,然后在代码中通过对应接口方法来调用。

2. 定义

慕课解释:select 标签用于映射 SQL 中的查询语句

3. 实例

MyBatis select 可分为xml注解两种使用方式。

3.1 xml 实例

将 select 查询写在 mapper.xml 文件中,比如:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.imooc.mybatis.mapper.UserMapper">
  <select id="selectUserAgeById" parameterType="java.lang.Integer" resultType="java.lang.Integer">
    SELECT age FROM imooc_user WHERE id = #{id}
  </select>
</mapper>

其中名为 selectUserAgeById 的 select 标签(一般以 id 做为名称),接收 Integer 类型的参数(parameterType),并返回 Integer 类型的结果(resultType);再看 select 标签中的查询语句,接收 id 参数,类型为 int,返回 age,类型为 int,二者一一对应。

3.2 参数符号

注意,在 select 标签中的 SQL 语句几乎与真实的 SQL 语句一致,但它的参数符号稍有不同:

#{id}

若以 #{}作为参数符号,MyBatis 则会创建一个预处理语句(PreparedStatement),它会被处理成?。如果你不希望使用预处理,那么可以使用${}参数符号,MyBatis 会将其以字符串的形式进行拼接,不过我们推荐你使用 #{},几乎所有人也都这样做。

3.3 注解实例

将 SQL 语句写在注解中,如下:

@Select("SELECT username FROM imooc_user WHERE id = #{id}")
String selectUsernameById(Integer id);

注解中的 select 语句无需再添加 id、parameterType 等属性,只需写上对应的 SQL 语句,MyBatis 会自动根据其修饰的方法来推断出这些参数。

TIPS: 提示,使用注解来书写 MyBatis 相对会方便一些,但是注解无法发挥 MyBatis 动态 SQL 真正的威力,因此大部分人都还是会选择 xml 的方式来书写 SQL,但是对于一些 demo 的展示,注解无疑容易上手一些。在后面的学习中,我们都会介绍到注解的使用,但是在实践中我们默认使用 xml 方式。

4. select 属性

select 标签支持很多属性来改变查询语句的行为。

我们摘取其中常见且重要的属性,如下表所示:

属性 描述
id 在命名空间中唯一的标识符
parameterType 语句的参数类型,默认可选,MyBatis 会自动推断
resultType 语句返回值类型,如果返回的是集合,那应该设置为集合包含的类型
resultMap 语句返回映射的 id;可以使用 resultType 或 resultMap,但不能同时使用。
flushCache 设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认为 false
useCache 设置为 true 后,本条语句的查询结果被二级缓存缓存起来,默认 select 标签为 true。
timeout 设置超时时间
fetchSize 设置预期返回的记录数量
statementType STATEMENT,PREPARED 或 CALLABLE 中的一个,默认为 PREPARED(预处理)

5. 参数

在上面的实例中,我们介绍了#{id}参数,这是参数的最简单情况,对于复杂情况,参数还有其它更多的妙用。

5.1 对象参数

有时候,参数可以是一个复杂的对象,如 Java 中的一个 User 类。

<select id="selectUserByAgeAndScore" parameterType="com.imooc.mybatis.model.User"
        resultType="com.imooc.mybatis.model.User">
  SELECT * FROM imooc_user WHERE age = #{age} AND score = #{score}
</select>

selectUserByAgeAndScore 查询的参数是一个复杂 Java 对象 User,当 User 作为参数对象时,User 中的属性都可作为查询语句的参数,如 age 和 score。

5.2 参数配置

#{}不仅可以传入参数名称,还可以传入参数类型和类型处理器。

比如:

#{age,javaType=int,jdbcType=int,typeHandler=IntegerTypeHandler}

其中 javaType 表示 age 的 Java 类型,jdbcType 表示 age 的数据库类型,typeHandler 表示 age 的类型处理器,关于类型处理器我们将在后面的章节介绍。

对于参数配置,90% 的情况你都只需要传入参数名即可,因为 MyBatis 都会自动推断出配置。

6. 实践

介绍了这么多概念,我们一起来实操巩固一下。

6.1 例1. 通过年龄和分数查询用户

请使用 MyBatis 完成在 imooc_user 表中通过年龄分数查询用户的功能。

分析:

按照 MyBatis 的开发模式,先在对应 UserMapper.xml 文件中添加通过年龄和分数查询用户的 select 标签,然后在 UserMapper.java 中增加上对应的方法即可。

步骤:

首先,我们在 com.imooc.mybatis 包下新建 model 包,用于保存数据库对象,并在 model 包下新建 User.java 类:

package com.imooc.mybatis.model;

public class User {
  private Long id;
  private String username;
  private Integer age;
  private Integer score;
  // 省略了 getter 和 setter 方法,请务必通过 IDE 生成,否则 MyBatis 无法自动映射
}

在 UserMapper.xml 文件中,我们新增 selectUserByAgeAndScore 标签,该 select 标签的作用是:通过年龄和分数查询用户。

<select id="selectUserByAgeAndScore" parameterType="com.imooc.mybatis.model.User"
        resultType="com.imooc.mybatis.model.User">
  SELECT * FROM imooc_user WHERE age = #{age} AND score = #{score}
</select>

然后在 UserMapper.java 接口中,我们新增对应的方法,方法接收复杂参数 User:

package com.imooc.mybatis.mapper;

import com.imooc.mybatis.model.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {
  User selectUserByAgeAndScore(User user);
}

结果:

通过如下代码,我们运行 selectUserByAgeAndScore 方法。

// 得到 mapper
UserMapper userMapper = session.getMapper(UserMapper.class);
User condition = new User();
condition.setAge(18);
condition.setScore(100);
// 调用方法
User user = userMapper.selectUserByAgeAndScore(condition);
// 得到 user
System.out.println(user);

输出结果为:

User{id=1, username='peter', age=18, score=100}

注意: 我们无法贴出全部的代码,这里的代码都是建立在之前的小节之上的,如果你感到疑惑,那么请先阅读环境搭建小节mapper 小节

7. 小结

  • MyBatis 虽然提供了 #{}${}两种方式来传递参数,但无疑#{}更加实用。
  • select 标签属性虽然多,但是大部分情况下都不会针对某一个 select 标签来定制化,多会在全局里进行配置。
  • 互联网的应用场景多数为读多写少,那么 select 肯定是使用最为广泛的标签了。