mybatis 详解(五)------动态SQL

  前面几篇博客我们通过实例讲解了用mybatis对一张表进行的CRUD操作,但是我们发现写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。

  那么怎么去解决这个问题呢?这就是本篇所讲的使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

  我们以 User 表为例来说明:

  

1、动态SQL: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 语句

2、动态SQL: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、动态SQL: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=?

4、动态SQL: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=?

  

5、动态SQL: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一样)

6、动态SQL: 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

    

7、动态SQL: 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:指定输入对象中的集合属性
  				item:每次遍历生成的对象
  				open:开始遍历时的拼接字符串
  				close:结束时拼接的字符串
  				separator:遍历对象之间需要拼接的字符串
  				select * from user 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集合查询user表数据
	@Test
	public void testSelectUserByListId(){
		String statement = "com.ys.po.userMapper.selectUserByListId";
		UserVo uv = new UserVo();
		List<Integer> ids = new ArrayList<>();
		ids.add(1);
		ids.add(2);
		ids.add(3);
		uv.setIds(ids);
		List<User> listUser = session.selectList(statement, uv);
		for(User u : listUser){
			System.out.println(u);
		}
		session.close();
	}

  

③、我们用 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:指定输入对象中的集合属性
  				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>

  

8、总结

  其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。

  

时间: 2024-10-10 06:28:31

mybatis 详解(五)------动态SQL的相关文章

MyBatis 之 使用五 动态SQL

MyBatis 提供使用 ognl 表达式动态生成 SQL的功能. 1. if 2. where where 可以自动处理掉第一个拼接条件里的 and <!-- 动态 sql 查询用户信息 -->   <select id="findUserByDynamicSql" parameterType="user" resultType="user">    select * from users    <!-- wher

mybatis入门基础(五)----动态SQL

一:动态SQL 1.1.定义 mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 1.2.案例需求 用户信息综合查询列表这个statement的定义使用动态sql,对查询条件进行判断,如果输入参数不为空才进行查询拼接. 1.3.UserMapper.xml 1 <!-- 用户信息综合查询 2 #{userCustom.sex}:取出pojo包装对象中性别值 3 ${userCustom.username}:取出pojo对象中用户名称 4 --> 5 &

详解Linq to SQL

第一部分,什么是Linq to sql Linq to sql(或者叫DLINQ)是LINQ(.NET语言集成查询)的一部分,全称基于关系数据的 .NET 语言集成查询,用于以对象形式管理关系数据,并提供了丰富的查询功能,它和Linq to xml.Linq to objects.Linq to dataset.Linq to entities等组成了强大的LINQ. 要学好LINQ查询语法,就不得不先理解C# 3.0的一些新特性,下面一一简单介绍. 第二部分,隐含类型局部变量 var age

一步一步学ios UITextView(多行文本框)控件的用法详解(五5.8)

本文转载至 http://wuchaorang.2008.blog.163.com/blog/static/48891852201232014813990/ 1.创建并初始化 创建UITextView的文件,并在.h文件中写入如下代码: [csharp] view plaincopy #import <UIKit/UIKit.h> @interface TextViewController : UIViewController <UITextViewDelegate> { UITe

MyBatis学习总结_11_MyBatis动态Sql语句

MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) trim where set foreach 1.if 对属性进行判断,如果不为空则执行判断条件 [html] view plaincopy <select id="selectByCriteria" parameterType="com.mu

MyBatis学习总结(六)——动态SQL

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) foreach where set trim 下面我们主要说 where set trim 这三个标签 1,where标签 <!-- 查询学生list,like姓名,=性别 --> <select id="getStudentListWhere" parameterTy

详解java动态代理

生活中的代理: 比如一个明星成名了以后,是需要有一个代理的,因为太多人想找他签名,应付不来,那么这个时候代理的作用是拦截你对真正明星的访问,他可以拦截下来收点费用,再叫真正的明星过来为你签名. 程序中的代理: 1,要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理.日志.计算方法的运行时间.事务管理.等等,你准备如何做? 2,编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码 下图显示了在程序中代理的调用原理(

mybatis 详解(三)------入门实例(基于注解)

1.创建MySQL数据库:mybatisDemo和表:user 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 2.建立一个Java工程,并导入相应的jar包,具体目录如下 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 3.在 MyBatisTest 工程中添加数据库配置文件 mybatis-configuration.xml 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 4.定义表所对应的实体类 详情

转:Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。

原文来自于:http://www.ituring.com.cn/article/128439 Windows下的PHP开发环境搭建——PHP线程安全与非线程安全.Apache版本选择,及详解五种运行模式. 今天为在Windows下建立PHP开发环境,在考虑下载何种PHP版本时,遭遇一些让我困惑的情况,为了解决这些困惑,不出意料地牵扯出更多让我困惑的问题. 为了将这些困惑一网打尽,我花了一下午加一晚上的时间查阅了大量资料,并做了一番实验后,终于把这些困惑全都搞得清清楚楚了. 说实话,之所以花了这么

.NET DLL 保护措施详解(五)常规条件下的破解

为了证实在常规手段破解下能有效保护程序核心功能(演示版本对AES加解密算法及数据库的密钥(一段字符串)进行了保护),特对此DLL保护思路进行相应的测试,包含了反编译及反射测试,看是否能得到AES加解密算法的密钥及数据库字符串. 反编译: 我这里使用了.net dll反编译工具ILSpy,以下为真实截图. 1. NetProtect.BLLDemo.dll 2. NetProtect.ConsoleApplication1.exe 3. NetProtect.CoreClr.dll 综合上图,可以