MyBatis的学习(四)——MyBatis动态SQL

一、动态SQL介绍

MyBatis 的强大特性之一便是它的动态 SQL。如果有使用 JDBC 或其他类似框架的经验,就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。

         动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNLStruts2语法) 的表达式来消除其他元素。

         mybatis 的动态sql语句是基于OGNL表达式的。可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:

  1. if 语句 (简单的条件判断)
  2. choose (when,otherwise) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似.
  3. trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)
  4. where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误)
  5. set (主要用于更新时)
  6. foreach (在实现 mybatis in 语句查询时特别有用)

二、动态SQL的使用

首先建立数据库和建立users表

建立users实体类:

package com.little.entity;

public class Users {
    private Integer id;
    private String name;
    private String sex;
    private String address;

    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;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Users{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

①if+where元素

根据name和sex元素来查询数据,如何name为空,sex不为空,根据sex来查询,反之根据name来查询,都为空就全查,都不为空就根据两者的条件来查询。

<select id="queryByNameAndSex" resultType="Users" parameterType="Users">
        select * from users
        <where>
            <if test="name != null">
                and name = #{name}
            </if>
            <if test="sex != null">
                and sex = #{sex}
            </if>
        </where>
    </select>

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

②if+set语句

比如在进行更新的时候,使用到set语句,MyBatis也有对应的set元素

<update id="updateUsersById" parameterType="Users">
		update users u
		<set>
			<if test="name != null and name != ''">
				u.name = #{name},
			</if>
			<if test="sex != null and sex != ''">
				u.sex = #{sex},
			</if>
		</set>
		where id=#{id}
	</update>

如果出现多余逗号 会自动去掉

③choose(when,otherwise)

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句

<select id="selectUsersByChoose" resultType="Users" parameterType="Users">
		select * from users
		<where>
			<choose>
				<when test="id !='' and id != null">
					id=#{id}
				</when>
				<when test="name !='' and name != null">
					and name=#{name}
				</when>
				<otherwise>
					and sex=#{sex}
				</otherwise>
			</choose>
		</where>
	</select>

这里就是只根据一个条件来进行查询,按照顺序进行

④trim

trim标记是一个格式化的标记,可以完成set或者是where标记的功能

用 trim 改写上面的 if+where 语句

<select id="selectUsersByNameAndSex" resultType="users" parameterType="Users">
		select * from users
		<trim prefix="where" prefixOverrides="and | or">
			<if test="name != null">
				and name=#{name}
			</if>
			<if test="sex != null">
				and sex=#{sex}
			</if>
		</trim>
	</select>

prefix:前缀      

prefixoverride:去掉第一个and或者是or

用 trim 改写上面的 if+set 语句

<!-- 根据 id 更新 user 表的数据 -->
	<update id="updateUsersById" parameterType="Users">
		update users u
		<trim prefix="set" suffixOverrides=",">
			<if test="name != null and name != ''">
				u.name = #{name},
			</if>
			<if test="sex != null and sex != ''">
				u.sex = #{sex},
			</if>
		</trim>
		where id=#{id}
	</update>

suffix:后缀  

 suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)

⑤SQL片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

比如:假如我们需要经常根据用户名和性别来进行联合查询,那么我们就把这个代码抽取出来,如下:

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

引用SQL片段

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

注意:最好基于 单表来定义 sql 片段,提高片段的可重用性

    sql 片段中不要包括 where

⑥foreach

需求:我们需要查询 users 表中 id 分别为1,2,3的用户

sql语句:select * from users where id=1 or id=2 or id=3 select * from users where id in (1,2,3)

建立一个 UserVo 类,里面封装一个 List<Integer> ids 的属性

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 users where id=1 or id=2 or id=3

<select id="selectUsersByListId" parameterType="UserVo"
		resultType="Users">
		select * from users
		<where>
			<!-- collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 
				separator:遍历对象之间需要拼接的字符串 select * from users where 1=1 and (id=1 or id=2 or 
				id=3) -->
			<foreach collection="ids" item="id" open="and (" close=")"
				separator="or">
				id=#{id}
			</foreach>
		</where>
	</select>

测试:

//根据id集合查询users表数据
	@Test
	public void testSelectUsersByListId(){
	    UserVo uv = new UserVo();
	    List<Integer> ids = new ArrayList<Integer>();
	    ids.add(1);
	    ids.add(2);
	    ids.add(3);
	    uv.setIds(ids);
	    List<Users> listUsers = mapper.selectUsersByListId(uv);
	    for(Users u : listUsers){
	        System.out.println(u);
	    }
	    session.close();
	}

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

<select id="selectUsersByListId" parameterType="Users" resultType="Users">
        select * from users
        <where>
            <!--
                collection:指定输入对象中的集合属性
                item:每次遍历生成的对象
                open:开始遍历时的拼接字符串
                close:结束时拼接的字符串
                separator:遍历对象之间需要拼接的字符串
                select * from user where 1=1 and id in (1,2,3)
              -->
            <foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
                #{id}
            </foreach>
        </where>
    </select>

单参数List的类型

<select id="dynamicForeachTest" resultType="Users">
		select * from users where id in
		<foreach collection="list" index="index" item="item" open="("
			separator="," close=")">
			#{item}
		</foreach>
	</select>

测试:

 public List<User> dynamicForeachTest(List<Integer> ids);


	@Test
	public void testSelectUserByListId1(){
	    List<Integer> ids = new ArrayList<Integer>();
	    ids.add(1);
	    ids.add(2);
	    ids.add(3);
	    List<Users> listUsers = mapper.dynamicForeachTest(ids);
	    for(Users u : listUsers){
	        System.out.println(u);
	    }
	}

单参数array数组的类型

<select id="dynamicForeach2Test" resultType="User">
		select * from users where id in
		<foreach collection="array" index="index" item="item" open="("
			separator="," close=")">
			#{item}
		</foreach>
	</select>
public List<Users> dynamicForeach2Test(Integer[] ids);
	@Test
	public void dynamicForeach2Test(){
	    Integer[] ids={1,2,3};
		List<Users> listUsers = mapper.dynamicForeach2Test(ids);
	    for(Users u : listUsers){
	        System.out.println(u);
	    }
	}

将参数封装成Map的类型

<select id="dynamicForeach3Test" resultType="User">
		select * from users where name like "%"#{name}"%" and id in
		<foreach collection="ids" index="index" item="item" open="("
			separator="," close=")">
			#{item}
		</foreach>
	</select>
public List<Users> dynamicForeach3Test(Map params);

测试:

@Test
	public void dynamicForeach3Test() {
		List ids = new ArrayList();
		ids.add(28);
		ids.add(29);
		ids.add(30);
		
		Map params = new HashMap();
		params.put("ids", ids);
		params.put("ame", "张");
		
		List<Users> listUsers = mapper.dynamicForeach3Test(params);
		for (Users u : listUsers) {
			System.out.println(u);
		}
	}

猜你喜欢

转载自blog.csdn.net/qq_41061437/article/details/83754195