MyBatis 超详细讲解动态SQL的实现
情景:
我们在使用JDBC或者其他类似的框架开发进行数据库开发时,通常要根据需求动手组装SQL,不用想都觉得是件很痛苦的事情了,而Mybatis框架提供的对SQL语句动态组装的功能,能很好地解决这个麻烦。
概述:
动态SQL是MyBatis框架的一个强大特性,MyBatis3可采用功能强大的基于OGNL的表达式来完成动态SQL,它删除了之前版本中需要了解的大多数元素,只使用不到原来一半的元素就能完成所需的工作。
SQL元素:
SQL元素 | 说明 |
---|---|
<if> | 判断语句,用于单条件分支判断 |
<choose> (<when>,<otherwise>) | 相当于Java中的switch...case...default语句,用于多条件分支判断 |
<where> | 简化SQL语句中的where的条件判断 |
<trim> | 可以灵活地去除多余的关键字 |
<set> | 解决动态更新语句 |
<foreach> | 循环语句,常用于in语句等列举条件中 |
<bind> | 从OGNL表达式中创建一个变量,并将其绑定到上下文,常用于模糊查询的SQL中 |
<if>:
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分
<?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="org.example.mapper.BookMapper"> <resultMap id="BookType" type="org.example.po.Book"> <id property="id" column="id"></id> <result property="bookName" column="bookName"></result> <result property="price" column="price"></result> <result property="publisher" column="publisher"></result> </resultMap> <select id="bookSelectById" parameterType="int" resultMap="BookType"> select * from t_book <where> <if test="id!=null and id!=''"> id=#{id} </if> </where> </select> <select id="bookSelectByname" parameterType="string" resultMap="BookType"> select * from t_book <where> <if test="bookNmae!=null and bookName!=''"> bookName LIKE concat('%',#{bookName},'%') </if> </where> </select> </mapper>
<choose>:
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
因为自己写的是单查询,引用官网代码。
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE' <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
<where>:
<where>标签相当于 where 1=1 ,主要用来简化SQL语句中的where条件判断,并能智能地处理and和or不必担心多余关键字导致的语法错误。代码参考<if>标签代码。
<trim>:
这个标签我觉得是最灵活的,trim元素也会自动识别其标签内是否有返回值,若有的话,则会在已包含的内容前加上某些前缀或者后缀(先判断是否有语句包含),用到的属性是
1、prefix(前缀),suffix(后缀)
还可以把包含内容的首内容或尾内容的符号去掉,用到的属性是
2、prefixOverride(前缀覆盖),suffixOverride(后缀覆盖)
可以说功能很强大,可以利用它来替代where元素,并实现与where元素相同的效果。
<?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="org.example.mapper.BookMapper"> <resultMap id="BookType" type="org.example.po.Book"> <id property="id" column="id"></id> <result property="bookName" column="bookName"></result> <result property="price" column="price"></result> <result property="publisher" column="publisher"></result> </resultMap> <update id="bookUpdate" parameterType="book"> UPDATE t_book <trim prefix="set" suffixOverrides=","> <if test="bookName!=null and bookName!=''">bookName=#{bookName},</if> <if test="price!=null and price!=''">price=#{price},</if> <if test="publisher!=null and publisher!=''">publisher=#{publisher}</if> WHERE id=#{id} </trim> </update> </mapper>
<set>:
set元素主要用于更新操作,它的主要功能和where元素差不多,主要是包含的语句前输入一个set,若包含的语句以逗号结束,则会自动把括号忽略掉,再配合if元素就可以动态地更新需要修改的字段;若不需要更改字段,则可以不再被更新。
把上面的代码修改一下:
<?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="org.example.mapper.BookMapper"> <resultMap id="BookType" type="org.example.po.Book"> <id property="id" column="id"></id> <result property="bookName" column="bookName"></result> <result property="price" column="price"></result> <result property="publisher" column="publisher"></result> </resultMap> <update id="bookUpdate" parameterType="book"> UPDATE t_book <!-- <trim prefix="set" suffixOverrides=",">--> <!-- <if test="bookName!=null and bookName!=''">bookName=#{bookName},</if>--> <!-- <if test="price!=null and price!=''">price=#{price},</if>--> <!-- <if test="publisher!=null and publisher!=''">publisher=#{publisher}</if>--> <!-- WHERE id=#{id}--> <!-- </trim>--> <set> <if test="bookName!=null and bookName!=''">bookName=#{bookName},</if> <if test="price!=null and price!=''">price=#{price},</if> <if test="publisher!=null and publisher!=''">publisher=#{publisher},</if> </set> WHERE id=#{id} </update> </mapper>
<foreach>:
foreach元素通常在构建in条件语句时使用,其使用方式如下。
(1). item: 表示每个元素迭代时的别名。
(2). index: 指定一个名称,用于表示在迭代过程中每次迭代的位置
(3). open: 表示该语句以什么开始(in语句以“( ”开始)
(4). separator: 表示每次进行迭代时以上面符号作为分隔符(in语句以“ ,”作为分隔符)
(5). close: 表示该语句以什么结束(in语句以“ )”结束)
(注意: 这个open,separator,close基本上就是固定格式了)
(6). collection: 表示最关键且最容易出错的属性,需格外注意。该属性必须指定,不同情况下该属性的值是不一样的,主要有三种情况:
1). 若入参为单参数且参数类型是一个list时,collection属性值为list
2). 若入参为单参数且参数类型是一个数组时,collection属性值为array
3). 若入参为多参数,需要将其封装为一个Map进行处理
格式:
<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P <where> <foreach item="item" index="id" collection="list" open="ID in (" separator="," close=")" nullable="true"> #{item} </foreach> </where> </select>
<bind>:
bind元素通常用于需要模糊查询的语句中,使用bind元素定义了一个name为pattern_username的变量,value的属性值就是拼接的查询字符串,其中_parameter.getTitle()表示传递进来的参数(也可以直接写成对应的参数变量名,如username)。
<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern_username" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>