mybatis的mapper映射文件

1 概述
1.1 应用架构
     mybatis 框架用于支持对关系数据库的操作,该体系的应用架构如下图所示:

    在 mybatis 框架体系中,主要的组件是:SqlSessionFactoryBean 和 MapperScannerConfigurer。SqlSessionFactoryBean 类依赖外部注入的数据源:DataSource。并有两个属性:configLocation 和 mapperLocations。
ConfigLocation 指定了 mybatis 配置文件的位置;mapperLocations 指定了多个 mapper 映射文件的位置。
MapperSacannerConfigurer 依赖 SqlSessionFactoryBean,并根据 basePackages 属性指定的 IDao 接口类所在的包位置,自动扫描该包路径,为每个 IDao 类创建一个 MapperFactoryBean 类。MapperFactoryBean 类会为它所对应的 IDao 接口类创建其具体的实现类实例,并将其注入到 service 层的业务代码中。
在 Spring boot 开发中,使用 @MapperScan 注解代替 MapperScannerConfigurer 类。它们的效果是一样的。
在使用 mybatis 框架实现数据库操作的时候,上图红色框部分的内容需要开发人员实现。
数据源是任何实现了 javax.sql.datasource 接口的类实例。例如:org.apache.tomcat.jdbc.pool.datasource,该数据源对应单库单表操作;或者 com.dangdang.ddframe.rdb.sharding.jdbc.core.datasource.ShardingDataSource, 该数据源对用分库,分表操作。
IDao 为数据操作接口,实现用户的数据操作逻辑。一般分为接口类和 po 类两部分。
配置文件分为:mybatis 配置文件和 mapper 配置文件。mybatis 配置文件主要用来设计 po 类的别名,方便对 po 类的引用;mapper 配置文件用来管理 SQL 语句。
1.2 主要开发要素
    在 mybatis 开发中,涉及到主要开发要素是:dao 接口类,mapper 映射文件,以及 po 类。它们之间的关系如下:

    dao 接口类中,定义了数据库操作的接口方法,主要包含增,删,改,查等接口方法;po 类定义接口方法的参数,可使用 po 类保存查询结果,或者为 insert,update 方法提供数据集参数。操作数据库表的 SQL 语句保存在 mapper 映射文件中。mapper 映射文件分别提供 select,insert,update,delete xml 元素,分别对应数据库的查询,插入,修改,删除操作。每一个 xml 元素通过 id 属性与 dao 接口类中的方法相互关联。

1.3 mapper 文件的结构
    mapper 映射文件是 xml 格式的配置文件,由一系列具有层级关系的元素组成。并且通过元素的属性,这些元素之间具有关联关系。具体情况如下图所示:

    在 mapper 映射文件中,主要包含如下配置元素:

  • mapper 元素。该元素是最顶层的配置元素,其属性 namespace 指向 IDao 类的全类型名,即:包路径 + 类名。在 mapper 元素下面,包含如下子元素:resultMap 元素,select 元素,insert 元素,update 元素,delete 元素。
  • resultMap 元素。建立数据库表的列名与 po 类的数据字段之间的映射关系。当 po 类的数据字段与数据库表不一致的时候,或者承载复杂查询结果的时候,使用 resultMap 配置;
  • select 元素。用来维护 select 语句。
  • insert 元素。用来维护 insert 语句。
  • update 元素。用来维护 update 语句。
  • delete 元素。用来维护 delete 语句。


2 文件示例
    在开发过程中,需要开发人员配置 mapper 映射文件,编写 Idao 类,以及 Idao 了所依赖的 po 类。具体示例如下:
2.1 mapper 映射文件
    mapper 配置文件的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lifeng.demo.mybatis.dao.IUserDao">
 
    <resultMap type="UserInfo" id="userData">
        <id property="id" column="f_id" />
        <result property="name" column="f_name" />
        <result property="birth" column="f_birth" />
        <result property="salary" column="f_salary" />
    </resultMap>
 
    <!-- id要与接口方法名相同 -->
    <!-- SQL语句中的参数名称(#{id}),要与java代码中的参数bean的数据字段相同,这里是UserInfo.id字段 -->
    <!-- type属性可省略 -->
    <insert id="insertUserInfoByBean">
        insert into t_user (f_id,f_name,f_birth,f_salary) values (#{id},#{name},#{birth},#{salary})
    </insert>
     
    <!-- @Param的参数必须与#{}中的参数一致 -->
    <insert id="insertUserInfo">
        insert into t_user (f_id,f_name,f_birth,f_salary) values (#{id},#{name},#{birth},#{salary})
    </insert>
 
    <insert id="insertUserInfoByBatch">
        insert into t_user (f_id,f_name,f_birth,f_salary) values
        <foreach collection="list" item="item" separator="," index="idx">
            (#{idx},#{item.name},#{item.birth},#{item.salary})
        </foreach>
    </insert>
 
    <!--resultMap属性的值是 resultMap配置节id的值。当承载返回结果的java bean数据字段与数据库表字段格式不一致时,使用resultMap -->
    <!-- 如果返回多行数据,会用list封装UserData -->
    <select id="listUserInfo" resultMap="userData">
        select * from t_user
    </select>
 
    <select id="getUserCount" resultType="int">
        select count(*) from
        t_user
    </select>
 
    <select id="listUserInfoToMap" resultType="map">
        select * from
        t_user
    </select>
 
    <select id="getUserInfoById" resultMap="userData">
        select * from t_user
        where f_id = #{id}
    </select>
 
    <select id="getUserInfoToMap" resultType="hashmap">
        select * from t_user
        where f_id=#{id}
    </select>
 
    <delete id="deleteAll">
        delete from t_user
    </delete>
 
    <delete id="deleteUserInfoById">
        delete from t_user where
        id=#{id}
    </delete>
 
    <update id="updateUserInfo">
        update t_user set f_name =
        #{name} where f_id =
        #{id}
    </update>
 
</mapper>

  

2.2 po 文件
    po 文件的示例如下:

package com.lifeng.demo.mybatis.dao.dto;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;

public class UserInfo implements Serializable {

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> serialVersionUID = 6730890636022435120L<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id;
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String name;
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date birth;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">double</span><span style="color: rgba(0, 0, 0, 1)"> salary;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getName() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setName(String name) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getBirth() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> birth;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setBirth(Date birth) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.birth =<span style="color: rgba(0, 0, 0, 1)"> birth;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">double</span><span style="color: rgba(0, 0, 0, 1)"> getSalary() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> salary;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setSalary(<span style="color: rgba(0, 0, 255, 1)">double</span><span style="color: rgba(0, 0, 0, 1)"> salary) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.salary =<span style="color: rgba(0, 0, 0, 1)"> salary;
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() {
    StringBuilder builder </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StringBuilder();
    builder.append(</span>"UserInfo = ["<span style="color: rgba(0, 0, 0, 1)">);
    builder.append(</span>"id:"<span style="color: rgba(0, 0, 0, 1)">);
    builder.append(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.id);

    builder.append(</span>" name:"<span style="color: rgba(0, 0, 0, 1)">);
    builder.append(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name);

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.birth != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
        builder.append(</span>" birth:"<span style="color: rgba(0, 0, 0, 1)">);
        builder.append(</span><span style="color: rgba(0, 0, 255, 1)">new</span> SimpleDateFormat("yyyyMMdd").format(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.birth));
    }

    builder.append(</span>" salary:"<span style="color: rgba(0, 0, 0, 1)">);
    builder.append(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.salary);

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> builder.toString();
}

}

2.3 dao 文件
    Dao 接口的示例如下:

package com.lifeng.demo.mybatis.dao;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;

import com.lifeng.demo.mybatis.dao.dto.UserInfo;

public interface IUserDao {

List</span>&lt;UserInfo&gt;<span style="color: rgba(0, 0, 0, 1)"> listUserInfo();

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getUserCount();

UserInfo getUserInfoById(</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> Id);

Map</span>&lt;String,Object&gt; getUserInfoToMap(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

@MapKey(</span>"f_id"<span style="color: rgba(0, 0, 0, 1)">)
Map</span>&lt;BigInteger,Map&lt;String,Object&gt;&gt;<span style="color: rgba(0, 0, 0, 1)"> listUserInfoToMap();

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> insertUserInfoByBean(UserInfo userInfo);

</span><span style="color: rgba(0, 0, 255, 1)">int</span> insertUserInfo(@Param("id") <span style="color: rgba(0, 0, 255, 1)">int</span> id,@Param("name") String userName,@Param("birth") Date birthDay,@Param("salary") <span style="color: rgba(0, 0, 255, 1)">double</span><span style="color: rgba(0, 0, 0, 1)"> salary);

</span><span style="color: rgba(0, 0, 255, 1)">int</span> insertUserInfoByBatch(List&lt;UserInfo&gt;<span style="color: rgba(0, 0, 0, 1)"> ls);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> updateUserInfo(UserInfo userInfo);

</span><span style="color: rgba(0, 0, 255, 1)">int</span> deleteUserInfoById(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> Id);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> deleteAll();

}

3 常用元素
3.1 resultMap
    使用 resultMap 配置节,建立 po 类的数据字段与数据库表的列名之间的映射关系。当 po 类的数据字段与数据库表的列名不一致的时候,可使用该配置。 resultMap 的代码示例如下:

<resultMap type="UserInfo" id="userData">
        <id property="id" column="f_id" />
        <result property="name" column="f_name" />
        <result property="birth" column="f_birth" />
        <result property="salary" column="f_salary" />
</resultMap>

    type 属性执行 po 类的全类型名,即:包名 + 类名。如果在 mybatis 配置文件中,为 po 类建立了别名,那么 type 属性可以引用该别名。
    id 属性应该全局唯一,它被 select 元素的 resultMap 属性引用。

    <id> 子元素用来建立 po 数据字段与数据库表主键列之间的映射关系。
    <result> 子元素用来建立 po 数据字段与数据库表非主键列之间的映射关系。
    property 属性用来指定 po 类的数据字段名。例如:private String name;该定义中的 name。
    column 属性用来指定数据库表的列名。
3.2 select
    在 mapper 文件中,使用 select 元素来管理 select 语句。
3.2.1 返回单值
当查询结果返回一个单值的时候,其配置如下:

<select id="getUserCount" resultType="int">
select count(*) from t_user
</select>

    使用 resultType 属性指定返回结果的数据类型,这里可以是 java 基本数据类型,如:int,String 等。

    在 IDao 类中,接口方法定义如下:

int getUserCount();

    方法的返回值类型是 int,与 resultType 的值对应;方法的名称是 getUserCount 与 id 属性的值对应。


3.2.2 返回单对象

    单对象的含义是:查询结果包含多个数据列,但只有一行数据。可以使用 javabean 或者 map 来保存查询结果。

3.2.2.1 通过 javabean 返回单对象
    通过 javabean 返回查询结果的配置如下:

<select id="getUserInfoById" resultMap="userData">
select * from t_user
where f_id = #{id}
</select>

    当 po 类的数据字段与数据库表的列名完全一致的时候,可使用 resultType=po 类全类型名,或 po 类别名 的方式指定查询结果的类型。

    当 po 类的数据字段与数据库表的列名不一致的时候,需要定义 resultMap 映射。在这种情况下,使用 resultMap 属性,该属性的值与 <resultMap> 元素的 id 属性的值相同。
    resultMap 与 resultType 不能同时使用。
    在 IDao 类中,接口方法的定义如下:

UserInfo getUserInfoById(int id)

    返回值的类型是 UserInfo,通过 <resultMap> 元素的配置,将该类型映射到 userData。在 <select> 元素中,通过 resultMap 属性引用 userData.

3.2.2.2 通过 map 返回单对象
    当查询结果是一个单对象,但是没有定义 po 类的时候,可使用 map 来承载查询结果。map 的 key 是数据库表的列名,value 是该列对应的值。mapper 映射文件的配置如下:

<select id="getUserInfoToMap" resultType="hashmap">
select * from t_user where f_id=#{id}
</select>

    resultType 属性的值设定为 hashmap,或者 map 即可。IDao 类中,接口方法定义如下:

Map<String,Object> getUserInfoToMap(int id);

 

3.2.3 返回数据集
    数据集的含义是:包含多行数据,每行数据包含多列。

3.2.3.1 通过 list 返回数据集
    当查询结果返回一个数据集的时候,mybatis 会将查询结果放入 list 中,然后返回。在这种情况下,resultTpye 或者 resultMap 属性指定的是 list 列表元素的类型,而非集合本身。mapper 映射文件的配置如下:

<select id="listUserInfo" resultMap="userData">
select * from t_user
</select>

    resultMap 或者 resultType 可以设定为 java bean ,也可设定为 map。该配置形式与返回单对象相同,其差别在 IDao 类中的接口方法定义:

list<UserInfo> listUserInfo();

    在定义接口方法的时候,需要使用 list 包装单值对象的类型。

 

3.2.3.2 通过 map 返回数据集
    该方式需要与注解 @MapKey 配合使用。map 的 key 是:数据库表中的任意一列,一般选具有索引性质的列,如:id,name 等。value 是:po 类的引用,或者另外一个 map 的引用。mapper 配置文件的内容如下:

<select id="listUserInfoToMap" resultType="map">
select * from t_user
</select>

    在 IDao 类中,接口方法的定义如下:

@MapKey("f_id")
Map<BigInteger,Map<String,Object>> listUserInfoToMap();

    在上面的示例中,value 的值是 map 类型。value 的值也可以是 po 类。在使用 po 类的时候,mapper 映射文件的配置如下:

<select id="listUserInfo" resultMap="userData">
select * from t_user
</select>

    在 IDao 类中,接口方法定义如下:

@MapKey("id")
map<int,UserInfo> listUserInfo();

 

3.3 结论
resultType 使用汇总如下,resultType 属性的值可以是如下情形:
      1. 基本数据类型,如:int,String 等;
      2.class 数据类型,如:java bean,这里输入的是全类型名或者别名;
      3.map 数据类型。包括:单对象和集合两种;
      4. 集合数据类型,是集合元素的类型,而非集合本身。
   resultMap 的使用汇总如下:
   该属性的值是:<resultMap> 元素的 id 属性的值。只有当 po 数据字段与数据库表列名不一致的时候,才使用。
3.3 insert
    在 mybatis 中,使用 <insert> 元素来管理 insert 语句。如果 sql 语句比较简单,可使用 @Insert 注解来代替 mapper 映射文件。
    如果需要插入的数据字段比较多,可以使用 po 类封装这些数据字段,示例如下:

<insert id="insertUserInfoByBean" parameterType="UserInfo">
insert into t_user (f_name,f_birth,f_salary) values (#{name},#{birth},#{salary})
</insert>

    IDao 类的接口方法定义如下:

int insertUserInfoByBean(UserInfo userInfo);

   <insert> 元素的 id 属性值是 IDao 类接口方法的名称。

    <insert> 元素的 parameterType 属性值可以省略。其值是接口方法参数的类型。如果接口方法的参数是 java bean,那么该值是全类型名(即:包名 + 类名),或者是类型的别名。
     注意:在 sql 语句中,如:#{name},#{birth} 等参数,其名称:name,birth,必须与接口参数 UserInfo 的数据字段一致。即:UserInfo 的数据字段名称必须是 name,birth。否则无法识别。

    如果需要插叙的数据字段比较少,那么可以直接传递给参数到接口方法中,mapper 映射文件的示例如下:

<insert id="insertUserInfo" >
insert into t_user (f_name,f_birth,f_salary) values (#{name},#{birth},#{salary})
</insert>

    IDao 接口类的定义如下:

int insertUserInfo(@Param("name") String userName,@Param("birth") Date birthDay,@Param("salary") double salary);

    注解 @Param 用来指定接口方法的参数名与 sql 语句中的参数名之间的映射。@Param 注解的参数,如:name,必须与 sql 语句中的参数,如:#{name} 中的 name 是完全一致的。

    如果 sql 语句比较简单,可以使用注解来代替 mapper 映射文件,示例如下:

@Insert("{insert into t_user (f_name,f_birth,f_salary) values (#{name},#{birth},#{salary})}")
int insertUserInfo(@Param("name") String userName,@Param("birth") Date birthDay,@Param("salary") double salary);

3.4 update

    <update> 元素用来维护 update 类型的 sql 语句。如果该 sql 语句比较简单,可以使用 @Update 注解代替 mapper 映射文件。

3.5 delete
    <delete> 元素用来维护 delete 类型的 sql 语句。如果该 sql 语句比较简单,可以使用 @Delete 注解来代替 mapper 映射文件。

3.6 动态 sql
    使用动态 sql 来支持复杂的 sql 语句。在动态 sql 部分,包含如下 xml 元素:
if, choose, when, otherwise, trim, where, set, foreach。

3.6.1 示例表
    以如下表结构示例动态 sql:

3.6.2 if 语句
    根据 username 和 sex 来查询数据。如果 username 为空,那么将只根据 sex 来查询;反之只根据 username 来查询。首先不使用 动态 SQL 来书写

<select id="selectUserByUsernameAndSex"
resultType="user" parameterType="com.ys.po.User">
<!-- 这里和普通的 sql 查询语句差不多,对于只有一个参数,后面的 #{id} 表示占位符,里面不一定要写 id,
写啥都可以,但是不要空着,如果有多个参数则必须写 pojo 类里面的属性 -->
select * from user where username=#{username} and sex=#{sex}
</select>

    上面的查询语句,我们可以发现,如果 #{username} 为空,那么查询结果也是空,如何解决这个问题呢?使用 if 来判断

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user where
<if test="username != null">
username=#{username}
</if>

<if test="username != null">
and sex
=#{sex}
</if>
</select>

      这样写我们可以看到,如果 sex 等于 null,那么查询语句为 select * from user where username=#{username}, 但是如果 usename 为空呢?那么查询语句为 select * from user where and sex=#{sex},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句

3.6.3 if + where 语句

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user
<where>
<if test="username != null">
username=#{username}
</if>

<if test="username != null">
and sex
=#{sex}
</if>
</where>
</select>

    这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头的,则它会剔除掉。

3.6.3 if + set 语句
     
同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?

<!-- 根据 id 更新 user 表的数据 -->
<update id="updateUserById" parameterType="com.ys.po.User">
update user u
<set>
<if test="username != null and username !=''">
u.username = #{username},
</if>
<if test="sex != null and sex !=''">
u.sex = #{sex}
</if>
</set>

where id=#{id}
</update>

 

    这样写,如果第一个条件 username 为空,那么 sql 语句为:update user u set u.sex=? where id=? ; 如果第一个条件不为空,那么 sql 语句为:update user u set u.username = ? ,u.sex = ? where id=?
3.6.4 choose(when,otherwise) 语句
    有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句

<select id="selectUserByChoose" resultType="com.ys.po.User" parameterType="com.ys.po.User">
select * from user
<where>
<choose>
<when test="id !=''and id != null">
id=#{id}
</when>
<when test="username !=''and username != null">
and username=#{username}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>

    也就是说,这里我们有三个条件,id,username,sex,只能选择一个作为查询条件

    如果 id 不为空,那么查询语句为:select * from user where id=?
    如果 id 为空,那么看 username 是否为空,如果不为空,那么语句为 select * from user where username=?;
          如果 username 为空,那么查询语句为 select * from user where sex=?

3.6.5 trim 语句
    trim 标记是一个格式化的标记,可以完成 set 或者是 where 标记的功能
  ①、用 trim 改写上面第二点的 if+where 语句

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user
<!-- <where>
<if test="username != null">
username=#{username}
</if>

<if test="username != null">
and sex
=#{sex}
</if>
</where> -->
<trim prefix="where" prefixOverrides="and | or">
<if test="username != null">
and username
=#{username}
</if>
<if test="sex != null">
and sex
=#{sex}
</if>
</trim>
</select>

 

prefix:前缀;prefixoverride:去掉第一个 and 或者是 or。
②、用 trim 改写上面第三点的 if+set 语句

<!-- 根据 id 更新 user 表的数据 -->
<update id="updateUserById" parameterType="com.ys.po.User">
update user u
<!-- <set>
<if test="username != null and username !=''">
u.username = #{username},
</if>
<if test="sex != null and sex !=''">
u.sex = #{sex}
</if>
</set> -->
<trim prefix="set" suffixOverrides=",">
<if test="username != null and username !=''">
u.username = #{username},
</if>
<if test="sex != null and sex !=''">
u.sex = #{sex},
</if>
</trim>

where id=#{id}
</update>    

 

 suffix:后缀  
suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的 and 一样) 
3.6.6 SQL 片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
比如:假如我们需要经常根据用户名和性别来进行联合查询,那么我们就把这个代码抽取出来,如下:

<!-- 定义 sql 片段 -->
<sql id="selectUserByUserNameAndSexSQL">
<if test="username != null and username !=''">
AND username = #{username}
</if>
<if test="sex != null and sex !=''">
AND sex = #{sex}
</if>
</sql>

 

引用 sql 片段

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user
<trim prefix="where" prefixOverrides="and | or">
<!-- 引用 sql 片段,如果 refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="selectUserByUserNameAndSexSQL"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</trim>
</select>

 

注意:①、最好基于 单表来定义 sql 片段,提高片段的可重用性
      ②、在 sql 片段中不要包括 where

3.6.7 foreach 语句
需求:我们需要查询 user 表中 id 分别为 1,2,3 的用户
  sql 语句:select * from user where id=1 or id=2 or id=3
       select * from user where id in (1,2,3)
①、建立一个 UserVo 类,里面封装一个 List<Integer> ids 的属性

package com.ys.vo;

import java.util.List;

public class UserVo {
//封装多个用户的 id
private List<Integer> ids;

public List<Integer> getIds() {
return ids;
}

public void setIds(List<Integer> ids) {
this.ids = ids;
}

}  

 

②、我们用 foreach 来改写 select * from user where id=1 or id=2 or id=3

<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
select * from user
<where>
<!--
collection: 指定输入对象中的集合属性。该属性的值有三种:list,array,map,根据传入的集合类型而设定该值。
item: 每次遍历生成的对象
index: 当前迭代的次数
open: 开始遍历时的拼接字符串
close: 结束时拼接的字符串
separator: 遍历对象之间需要拼接的字符串
select * from user where 1=1 and (id=1 or id=2 or id=3)
-->
<foreach collection="list" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>

 

③、我们用 foreach 来改写 select * from user where id in (1,2,3)

<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
select * from user
<where>
<!--
collection: 指定输入对象中的集合属性. 该属性的值有三种:list,array,map,根据传入的集合类型而设定该值。
item: 每次遍历生成的对象
index: 当前迭代的次数
open: 开始遍历时的拼接字符串
close: 结束时拼接的字符串
separator: 遍历对象之间需要拼接的字符串
select * from user where 1=1 and id in (1,2,3)
-->
<foreach collection="list" item="id" open="and id in (" close=")" separator=",">
#{id}
</foreach>
</where>
</select>