1、Example 类详解

1.1 整体构造

public class User {

    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }

    public User() {
    }

    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class UserExample {

    /**
     * 升序还是降序
     * 参数格式:字段 + 空格 + ASC / DESC
     * 参考用例:userExample.setOrderByClause("username asc");
     */
    protected String orderByClause;

    /**
     * 去除重复
     * true 为去重;false为不去重
     * 参考用例:userExample.setDistinct(true);
     */
    protected boolean distinct;

    /**
     * 自定义查询条件
     * Criteria 的集合,集合中对象是由 or 连接
     * 为什么是 or 连接,主要在于 mapper.xml 文件的内部实现
     */
    protected List<Criteria> oredCriteria;

    /**
     * 空构造函数
     * new UserExample() 时在内部自动创建一个 ArrayList 数组用于存放自定义查询条件
     */
    public UserExample() {
        oredCriteria = new ArrayList<Criteria>();
    }

    /**
     * 39-52 行为字段 orderByClause 和 distinct 的 getter、setter 方法
     * 53-55 行为 oredCriteria 字段的 getter 方法
     */
    public void setOrderByClause(String orderByClause) {
        System.out.println("设置 orderByClause 属性为 " + orderByClause);
        this.orderByClause = orderByClause;
    }
    public String getOrderByClause() {
        return orderByClause;
    }
    public void setDistinct(boolean distinct) {
        System.out.println("设置 distinct 属性为 " + distinct);
        this.distinct = distinct;
    }
    public boolean isDistinct() {
        return distinct;
    }
    public List<Criteria> getOredCriteria() {
        return oredCriteria;
    }

    /**
     * 内部类 Criteria 包含一个 Cretiron 的集合
     * 每一个 Criteria 对象内包含的 Cretiron 之间是由 AND 连接的
     */
    public static class Criteria extends GeneratedCriteria {
        protected Criteria() {
            super();
        }
    }

    /**
     * 将传来的条件放入“自定义查询集合oredCriteria”中
     * 注意:条件与条件之间的连接用 OR
     */
    public void or(Criteria criteria) {
        oredCriteria.add(criteria);
    }

    /**
     * 内部调用 createCriteriaInternal() 方法
     * 总结:创建的规则,加入到规则集中,并且是or的关系。
     */
    public Criteria or() {
        Criteria criteria = createCriteriaInternal();
        oredCriteria.add(criteria);
        return criteria;
    }

    /**
     * 内部调用 createCriteriaInternal() 方法
     * 总结:当没有规则时,则加入到现有规则;但有规则时,不再加入到现有规则,只是返回创建的规则
     */
    public Criteria createCriteria() {
        Criteria criteria = createCriteriaInternal();
        if (oredCriteria.size() == 0) {
            oredCriteria.add(criteria);
        }
        return criteria;
    }

    /**
     * 内部类
     * 其方法内部创建出 Criteria 对象,Criteria 又继承 GeneratedCriteria,内部又创建 List<Criterion> criteria 集合
     */
    protected Criteria createCriteriaInternal() {
        Criteria criteria = new Criteria();
        return criteria;
    }

    /**
     * 清空 UserExample 类中的各项属性
     */
    public void clear() {
        oredCriteria.clear();
        orderByClause = null;
        distinct = false;
    }

    // 下面会有详细介绍,此处暂时省略
    protected abstract static class GeneratedCriteria {...}

    // 下面会有详细介绍,此处暂时省略
    public static class Criterion {...}
}

1.2 Criterion 类

/**
 * 是最基本,最底层的 WHERE 条件,用于字段级的筛选,可以把它想成 WHERE 条件的集合
 * Criteria 包含一个 Criterion 的集合,每一个 Criteria 对象内包含的 Criterion 之间是由AND连接的。
 */
public static class Criterion {
   private String condition;       // 用于后续填写状态的字段:比如可以赋值为 id is not null
    private Object value;           // 第一个参数值
    private Object secondValue;     // 第二个参数值
    private boolean noValue;        // 用来判断是否存在参数值
    private boolean singleValue;    // 用来判断有几个参数值
    private boolean betweenValue;   // 用来判断是否有区间的标志,比如:age < 值1 and age > 值2 这种形式
    private boolean listValue;      // 用来判断是否存在参数类型是集合类

    // 相应字段的 Getter 方法
    public String getCondition() { return condition;}
    public Object getValue() { return value; }
    public Object getSecondValue() { return secondValue; }
    public boolean isNoValue() { return noValue; }
    public boolean isSingleValue() { return singleValue; }
    public boolean isBetweenValue() { return betweenValue; }
    public boolean isListValue() { return listValue; }

    /**
     * 以下是三种不同的构造方法
     */
    // 适用于没有参数值的传递的构造
    protected Criterion(String condition) {
        super();
        this.condition = condition;
        this.noValue = true;
    }

    // 适合只有一个参数的构造
    protected Criterion(String condition, Object value) {
        super();
        this.condition = condition;
        this.value = value;
        if (value instanceof List<?>) {
            this.listValue = true;
        } else {
            this.singleValue = true;
        }
    }

    // 适合两个参数的构造,也可以理解成一般这种形式就是区间
    protected Criterion(String condition, Object value, Object secondValue) {
        super();
        this.condition = condition;
        this.value = value;
        this.secondValue = secondValue;
        this.betweenValue = true;
    }
}

可能只看这一部分有些云里雾里,需要结合着后面的案例一起到时候便会恍然大悟

1.3 GeneratedCriteria 类

/**
 * MyBatis 中逆向工程中的代码模型
 * 同时也是 Criteria 类的父类
 */
protected abstract static class GeneratedCriteria {
    // List<Criterion> 为封装查询条件的集合,其中 Criterion 把它想成 WHERE 条件的集合
    protected List<Criterion> criteria;

    public List<Criterion> getCriteria() {
        return criteria;
    }

    protected GeneratedCriteria() {
        super();
        criteria = new ArrayList<Criterion>();// 初始化构造数组集合 criteria
    }

    /**
     * 判断 criteria 集合中是否有值,也就是是否有“查询条件”
     * @return
     */
    public boolean isValid() {
        return criteria.size() > 0;
    }

    // 3种往 criteria 集合中放“查询条件”的方法,也刚好分别对应上述 Criterion 类的三种构造方法

    protected void addCriterion(String condition) {
        if (condition == null) {
            throw new RuntimeException("Value for condition cannot be null");
        }
        criteria.add(new Criterion(condition));
    }

    protected void addCriterion(String condition, Object value, String property) {
        if (value == null) {
            throw new RuntimeException("Value for " + property + " cannot be null");
        }
        criteria.add(new Criterion(condition, value));
    }

    protected void addCriterion(String condition, Object value1, Object value2, String property) {
        if (value1 == null || value2 == null) {
            throw new RuntimeException("Between values for " + property + " cannot be null");
        }
        criteria.add(new Criterion(condition, value1, value2));
    }


    // 以下全是 andXXX 等代码方法

    public Criteria andIdIsNull() {
        addCriterion("id is null");
        return (Criteria) this;
    }

    public Criteria andIdIsNotNull() {
        addCriterion("id is not null");
        return (Criteria) this;
    }

    public Criteria andIdEqualTo(Integer value) {
        addCriterion("id =", value, "id");
        return (Criteria) this;
    }

    public Criteria andIdNotEqualTo(Integer value) {
        addCriterion("id <>", value, "id");
        return (Criteria) this;
    }

    public Criteria andIdGreaterThan(Integer value) {
        addCriterion("id >", value, "id");
        return (Criteria) this;
    }

    public Criteria andIdGreaterThanOrEqualTo(Integer value) {
        addCriterion("id >=", value, "id");
        return (Criteria) this;
    }

    public Criteria andIdLessThan(Integer value) {
        addCriterion("id <", value, "id");
        return (Criteria) this;
    }

    public Criteria andIdLessThanOrEqualTo(Integer value) {
        addCriterion("id <=", value, "id");
        return (Criteria) this;
    }

    public Criteria andIdIn(List<Integer> values) {
        addCriterion("id in", values, "id");
        return (Criteria) this;
    }

    public Criteria andIdNotIn(List<Integer> values) {
        addCriterion("id not in", values, "id");
        return (Criteria) this;
    }

    public Criteria andIdBetween(Integer value1, Integer value2) {
        addCriterion("id between", value1, value2, "id");
        return (Criteria) this;
    }

    public Criteria andIdNotBetween(Integer value1, Integer value2) {
        addCriterion("id not between", value1, value2, "id");
        return (Criteria) this;
    }

    public Criteria andNameIsNull() {
        addCriterion("name is null");
        return (Criteria) this;
    }

    public Criteria andNameIsNotNull() {
        addCriterion("name is not null");
        return (Criteria) this;
    }

    public Criteria andNameEqualTo(String value) {
        addCriterion("name =", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameNotEqualTo(String value) {
        addCriterion("name <>", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameGreaterThan(String value) {
        addCriterion("name >", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameGreaterThanOrEqualTo(String value) {
        addCriterion("name >=", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameLessThan(String value) {
        addCriterion("name <", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameLessThanOrEqualTo(String value) {
        addCriterion("name <=", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameLike(String value) {
        addCriterion("name like", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameNotLike(String value) {
        addCriterion("name not like", value, "name");
        return (Criteria) this;
    }

    public Criteria andNameIn(List<String> values) {
        addCriterion("name in", values, "name");
        return (Criteria) this;
    }

    public Criteria andNameNotIn(List<String> values) {
        addCriterion("name not in", values, "name");
        return (Criteria) this;
    }

    public Criteria andNameBetween(String value1, String value2) {
        addCriterion("name between", value1, value2, "name");
        return (Criteria) this;
    }

    public Criteria andNameNotBetween(String value1, String value2) {
        addCriterion("name not between", value1, value2, "name");
        return (Criteria) this;
    }

    public Criteria andAgeIsNull() {
        addCriterion("age is null");
        return (Criteria) this;
    }

    public Criteria andAgeIsNotNull() {
        addCriterion("age is not null");
        return (Criteria) this;
    }

    public Criteria andAgeEqualTo(Integer value) {
        addCriterion("age =", value, "age");
        return (Criteria) this;
    }

    public Criteria andAgeNotEqualTo(Integer value) {
        addCriterion("age <>", value, "age");
        return (Criteria) this;
    }

    public Criteria andAgeGreaterThan(Integer value) {
        addCriterion("age >", value, "age");
        return (Criteria) this;
    }

    public Criteria andAgeGreaterThanOrEqualTo(Integer value) {
        addCriterion("age >=", value, "age");
        return (Criteria) this;
    }

    public Criteria andAgeLessThan(Integer value) {
        addCriterion("age <", value, "age");
        return (Criteria) this;
    }

    public Criteria andAgeLessThanOrEqualTo(Integer value) {
        addCriterion("age <=", value, "age");
        return (Criteria) this;
    }

    public Criteria andAgeIn(List<Integer> values) {
        addCriterion("age in", values, "age");
        return (Criteria) this;
    }

    public Criteria andAgeNotIn(List<Integer> values) {
        addCriterion("age not in", values, "age");
        return (Criteria) this;
    }

    public Criteria andAgeBetween(Integer value1, Integer value2) {
        addCriterion("age between", value1, value2, "age");
        return (Criteria) this;
    }

    public Criteria andAgeNotBetween(Integer value1, Integer value2) {
        addCriterion("age not between", value1, value2, "age");
        return (Criteria) this;
    }
}

发现,下面基本都是类似这种 andXxxxXxx 形式的方法,因此我们进行整理总结一下:

方法 说明
andXxxIsNull 添加字段 xxx 为 null 的条件
andXxxIsNotNull 添加字段 xxx 不为 null 的条件
andXxxEqualTo(value) 添加 xxx 字段等于 value 条件
andXxxNotEqualTo(value) 添加 xxx 字段不等于 value 条件
andXxxGreaterThan(value) 添加 xxx 字段大于 value 条件
andXxxGreaterThanOrEqualTo(value) 添加 xxx 字段大于等于 value 条件
andXxxLessThan(value) 添加 xxx 字段小于 value 条件
andXxxLessThanOrEqualTo(value) 添加 xxx 字段小于等于 value 条件
andXxxIn(List<?>) 添加 xxx 字段值在 List<?> 条件
andXxxNotIn(List<?>) 添加 xxx 字段值不在 List<?> 条件
andXxxLike(“%”+value+”%”) 添加 xxx 字段值为 value 的模糊查询条件
andXxxNotLike(“%”+value+”%”) 添加 xxx 字段值不为 value 的模糊查询条件
andXxxBetween(value1, value2) 添加 xxx 字段值在 value1 和 value2 之间条件
andXxxNotBetween(value1, value2) 添加 xxx 字段值不在 value1和 value2 之间条件

我们再结合一些实例代码进行辅助理解:

image-20220201125336136

至此我们大概了解了 GeneratedCriteria 类,可以说只要创建了 Criteria 类的对象,他就会调用父类构造方法,创建出一个 List<Criterion> criteria 集合用于存放封装条件。

1.4 Criteria 类

/**
  * 内部类 Criteria 包含一个 Cretiron 的集合
  * 每一个 Criteria 对象内包含的 Cretiron 之间是由 AND 连接的
  */
public static class Criteria extends GeneratedCriteria {
    protected Criteria() {
        super();
    }
}

1.5 类中其他方法

/**
 * 创建出 Criteria 对象(继承 GeneratedCriteria),其内部创建 List<Criterion> criteria 集合
 */
protected Criteria createCriteriaInternal() {
    Criteria criteria = new Criteria();
    return criteria;
}

/**
 * 内部调用 createCriteriaInternal() 方法
 * 总结:当没有规则时,则加入到现有规则;但有规则时,不再加入到现有规则,只是返回创建的规则
 */
public Criteria createCriteria() {
    Criteria criteria = createCriteriaInternal();
    if (oredCriteria.size() == 0) {
        oredCriteria.add(criteria);
    }
    return criteria;
}

/**
 * 内部调用 createCriteriaInternal() 方法
 * 总结:创建的规则,加入到规则集中,并且是or的关系。
 */
public Criteria or() {
    Criteria criteria = createCriteriaInternal();
    oredCriteria.add(criteria);
    return criteria;
}

/**
 * 将传来的条件放入“自定义查询集合oredCriteria”中
 * 注意:条件与条件之间的连接用 OR
 */
public void or(Criteria criteria) {
    oredCriteria.add(criteria);
}

/**
 * 清空 UserExample 类中的各项属性
 */
public void clear() {
    oredCriteria.clear();
    orderByClause = null;
    distinct = false;
}

1.6 两种使用方式

image-20220201184159342

以上方式无论是哪种方式,最后对会在内部调用 createCriteriaInternal(); 方法:

image-20220201233646329

1.7 再理解 Criteria 和 Criterion

通过整理,我们发现 List<Criteria> oredCriteria = new ArrayList<Criteria>(); 可以理解为一种类似 HashMap 的结构,结合代码与图示:

image-20220202002415927

@Test
public void test02() {
    UserExample userExample = new UserExample();
    UserExample.Criteria criteria1 = userExample.createCriteria();
    criteria1.andNameIsNotNull();
    criteria1.andAgeIsNull();

    UserExample.Criteria criteria2 = userExample.createCriteria();
    criteria2.andNameLike("用户1");
    criteria2.andIdEqualTo(2);
    userExample.or(criteria2);

    UserExample.Criteria criteria3 = userExample.createCriteria();
    criteria3.andAgeBetween(1,2);
    userExample.or(criteria3);

    UserExample.Criteria criteria4 = userExample.createCriteria();
    List<Integer> idList = new ArrayList<>();
    idList.add(1);
    idList.add(2);
    idList.add(3);
    idList.add(4);
    criteria4.andIdIn(idList);
    userExample.or(criteria4);

    System.out.println(userMapper.selectByExample(userExample));
}

2、Mapper.xml 文件

2.1 整体构造

<?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.yth.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="com.yth.entity.User">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
    </resultMap>

    <sql id="Example_Where_Clause">
        <where>
            <foreach collection="oredCriteria" item="criteria" separator="or">
                <if test="criteria.valid">
                    <trim prefix="(" suffix=")" prefixOverrides="and">
                        <foreach collection="criteria.criteria" item="criterion">
                            <choose>
                                <when test="criterion.noValue">
                                    and ${criterion.condition}
                                </when>
                                <when test="criterion.singleValue">
                                    and ${criterion.condition} #{criterion.value}
                                </when>
                                <when test="criterion.betweenValue">
                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                                </when>
                                <when test="criterion.listValue">
                                    and ${criterion.condition}
                                    <foreach collection="criterion.value" item="listItem" open="(" close=")"
                                             separator=",">
                                        #{listItem}
                                    </foreach>
                                </when>
                            </choose>
                        </foreach>
                    </trim>
                </if>
            </foreach>
        </where>
    </sql>

    <sql id="Update_By_Example_Where_Clause">
        <where>
            <foreach collection="example.oredCriteria" item="criteria" separator="or">
                <if test="criteria.valid">
                    <trim prefix="(" suffix=")" prefixOverrides="and">
                        <foreach collection="criteria.criteria" item="criterion">
                            <choose>
                                <when test="criterion.noValue">
                                    and ${criterion.condition}
                                </when>
                                <when test="criterion.singleValue">
                                    and ${criterion.condition} #{criterion.value}
                                </when>
                                <when test="criterion.betweenValue">
                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                                </when>
                                <when test="criterion.listValue">
                                    and ${criterion.condition}
                                    <foreach collection="criterion.value" item="listItem" open="(" close=")"
                                             separator=",">
                                        #{listItem}
                                    </foreach>
                                </when>
                            </choose>
                        </foreach>
                    </trim>
                </if>
            </foreach>
        </where>
    </sql>

    <sql id="Base_Column_List">
        id, name, age
    </sql>

    <select id="selectByExample" resultMap="BaseResultMap" parameterType="com.yth.entity.UserExample">
        select
        <if test="distinct">
            distinct
        </if>
        <include refid="Base_Column_List"/>
        from t_user
        <if test="_parameter != null">
            <include refid="Example_Where_Clause"/>
        </if>
        <if test="orderByClause != null">
            order by ${orderByClause}
        </if>
    </select>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer">
        select
        <include refid="Base_Column_List"/>
        from t_user
        where id = #{id,jdbcType=INTEGER}
    </select>
    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
        delete from t_user
        where id = #{id,jdbcType=INTEGER}
    </delete>
    <delete id="deleteByExample" parameterType="com.yth.entity.UserExample">
        delete from t_user
        <if test="_parameter != null">
            <include refid="Example_Where_Clause"/>
        </if>
    </delete>
    <insert id="insert" parameterType="com.yth.entity.User">
        insert into t_user (id, name, age
        )
        values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}
        )
    </insert>
    <insert id="insertSelective" parameterType="com.yth.entity.User">
        insert into t_user
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                id,
            </if>
            <if test="name != null">
                name,
            </if>
            <if test="age != null">
                age,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">
                #{id,jdbcType=INTEGER},
            </if>
            <if test="name != null">
                #{name,jdbcType=VARCHAR},
            </if>
            <if test="age != null">
                #{age,jdbcType=INTEGER},
            </if>
        </trim>
    </insert>
    <select id="countByExample" parameterType="com.yth.entity.UserExample" resultType="java.lang.Integer">
        select count(*) from t_user
        <!--
            如果只有一个参数,那么 _parameter 代表该参数
            如果有多个参数,那么 _parameter 可以 get(0) 得到第一个参数
        -->
        <if test="_parameter != null">
            <include refid="Example_Where_Clause"/>
        </if>
    </select>
    <update id="updateByExampleSelective" parameterType="map">
        update t_user
        <set>
            <if test="record.id != null">
                id = #{record.id,jdbcType=INTEGER},
            </if>
            <if test="record.name != null">
                name = #{record.name,jdbcType=VARCHAR},
            </if>
            <if test="record.age != null">
                age = #{record.age,jdbcType=INTEGER},
            </if>
        </set>
        <if test="_parameter != null">
            <include refid="Update_By_Example_Where_Clause"/>
        </if>
    </update>
    <update id="updateByExample" parameterType="map">
        update t_user
        set id = #{record.id,jdbcType=INTEGER},
        name = #{record.name,jdbcType=VARCHAR},
        age = #{record.age,jdbcType=INTEGER}
        <if test="_parameter != null">
            <include refid="Update_By_Example_Where_Clause"/>
        </if>
    </update>
    <update id="updateByPrimaryKeySelective" parameterType="com.yth.entity.User">
        update t_user
        <set>
            <if test="name != null">
                name = #{name,jdbcType=VARCHAR},
            </if>
            <if test="age != null">
                age = #{age,jdbcType=INTEGER},
            </if>
        </set>
        where id = #{id,jdbcType=INTEGER}
    </update>
    <update id="updateByPrimaryKey" parameterType="com.yth.entity.User">
        update t_user
        set name = #{name,jdbcType=VARCHAR},
        age = #{age,jdbcType=INTEGER}
        where id = #{id,jdbcType=INTEGER}
    </update>
</mapper>

我们要主要解析的(具体在下面常用方法中配合实例分析):

  • Example_Where_Clause

  • Update_By_Example_Where_Clause

下面以 Update_By_Example_Where_Clause 举例:

image-20220202005103995

每一个 <when test="">标签对应着一个:

image-20220202005145819

2.2 mapper 接口中常用方法解析

方法 功能说明
int countByExample(UserExample example); 按条件计数
int deleteByExample(UserExample example); 按条件删除
int deleteByPrimaryKey(Integer id); 按主键删除
int insert(User record); 传入对象新增数据
int insertSelective(User record); 传入对象新增值不为 null 的字段
List<User> selectByExample(UserExample example); 按条件查询
User selectByPrimaryKey(Integer id); 按主键查询
int updateByExampleSelective(User record, UserExample example); 按条件更新值不为 null 的字段
int updateByExample(User record, UserExample example); 按条件更新
int updateByPrimaryKeySelective(User record); 按主键更新值不为 null 的字段
int updateByPrimaryKey(User record); 按主键更新

END

本文作者:
文章标题:MyBatis 逆向工程生成类详解
本文地址:https://www.pendulumye.com/mybatis/471.html
版权说明:若无注明,本文皆PendulumYe原创,转载请保留文章出处。
最后修改:2022 年 08 月 02 日
千山万水总是情,给个一毛行不行💋