Mybatis07--动态SQL

介绍:

  • 什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.本质上还是拼接语句

  • 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

  • 使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

  • 如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

    • if
    • choose (when, otherwise)
    • trim (where, set)
    • foreach

搭建环境

在这里插入图片描述

  • 导入的插件还是和以前一样
  • 数据库字段
drop table if exists blog;

CREATE TABLE `blog`
(
    `id`          varchar(50)  NOT NULL COMMENT '博客id',
    `title`       varchar(100) NOT NULL COMMENT '博客标题',
    `author`      varchar(30)  NOT NULL COMMENT '博客作者',
    `create_time` varchar(30)  NOT NULL COMMENT '创建时间',
    `views`       int(30)      NOT NULL COMMENT '浏览量'
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
  • 实体类Blog.java
package pojo;
import java.util.Date;
import lombok.Data;
@Data
public class Blog {
	private String id;
	private String title;
	private String author;
	private String createTime; //注意:属性名和字段名不一致,下面在配置文件中加入一行解决
	private int views;
}
  • 工具类MybatisUtils.java也和以前一样
  • db.properties 也和以前一样
  • 配置文件mybatis-config.xml也和以前一样,只是改了下面的这些位置
<settings>
	<!-- 开启驼峰命名,解决上面的字段名不一样的问题 -->
	<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--下面的这个注册mapper也要改了-->
<mappers>
	<package name="com.wu.mapper"/>
</mappers>
  • BlogMapper.java(接口)
package mapper;
public interface BlogMapper {

}
  • BlogMapper.xml(用来编写sql语句)
<?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.wu.mapper.BlogMapper">
	
</mapper>

if

1、编写接口类

//根据条件查询博客
List<Blog> queryBlogIf(Map map);

2、编写SQL语句

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:

<!--select * from blog where title =  #{title} -->
<select id="queryBlogIF" parameterType="map" resultType="Blog">	
    select * from blog	
    where  1=1 
    <if test="title != null">
       and  title =  #{title}
    </if>
</select>

这个看上去没问题,如果又改了一种情况后:

<select id="queryBlogIF" parameterType="map" resultType="Blog">	
	select * from blog	
    where  
    <if test="title != null">
     	title =  #{title}
 	</if>
	<if test="author != null">
        and author = #{author} 
 	</if>
</select>

如果不满足第一个条件反而满足了第二个条件呢,它的执行语句会变成这样

select * from blog where and  author = #{author} 

这样的话,sql语句明显错误,多了一个and,所以改造一下上面的,用where标签来代替

  • where
<select id="queryBlogIF" parameterType="map" resultType="Blog">	
	select * from blog	
    <where>
  		<if test="title != null">
            and title =  #{title}
        </if>
	    <if test="author != null">
	 	    and author = #{author} 
 	    </if>
   </where>
</select>
  • where标签很智能,如果你下面的条件都不满足,它会自动去掉where标签
  • where 元素只会在子元素返回任何内容的情况下才插入 “where” 子句。
  • 而且,若子句的开头为 “and” 或 “or”,where 元素也会将它们去除。所以大多数情况下还是要用where标签

3、测试

@Test
//自己在数据库中添加数据后,多测几遍,还有上面的sql语句也可以改改
public void queryBlogIF() {
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
	Map map = new HashMap();
	map.put("author", "某某某");
	List<Blog> blogs = mapper.queryBlogIF(map);
	for (Blog blog : blogs) {
		System.out.println(blog);
	}
	sqlSession.close();
}

choose (when, otherwise)

1、编写接口方法

List<Blog> queryBlogChoose(Map map);	

2、编写SQL语句

<!--select * from blog .... -->
<select id="queryBlogChoose" parameterType="map" resultType="Blog">
	select * from blog
	<where>
		<!-- choose 标签下的都可以不加and ,otherwise也可以不写,因为这个里面只会执行一个条件,可以想象成switch -->
		<choose>
			<when test="title!=null">
				and title = #{title}
			</when>
			<when test="author!=null">
				and author = #{author}
			</when>
			<!--不满足上面的条件才会执行它-->
			<otherwise>  
				and views >= #{views} 
			</otherwise>
		</choose>
	</where>
</select>

3、测试

自己还是把上面的sql语句改改,把下面的测试改改,多测试几遍应该就差不多了

@Test
public void queryBlogChoose() {
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
	Map map = new HashMap();
	map.put("views", 8000);
	List<Blog> blogs = mapper.queryBlogChoose(map);
	for (Blog blog : blogs) {
		System.out.println(blog);
	}
	sqlSession.close();
}

它有点像 Java 中的 switch 语句。它只会满足其中的一种条件,比如,第一个条件满足后,后面的条件就没管了

Set

1、编写接口方法

void updateBlog(Map map);

2、编写SQL语句

<!--update blog set ...... -->
<update id="updateBlog" parameterType="map">
	update blog
	<set>
		<if test="title!=null">
			title  = #{title},
		</if>
		<if test="author!=null">
			author = #{author},
		</if>
		<if test="views!=null">
			views = #{views},
		</if>
	</set>
	where id = #{id}
</update>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号

3、测试

@Test
public void updateBlog() {
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);	
	Map map = new HashMap();
	map.put("title", "Java不简单啊");
	map.put("id", "1");
	mapper.updateBlog(map);
	sqlSession.close();
}

foreach

  • foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
  • 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

1、编写接口方法

//我们需要查询 blog 表中 id 分别为1,2,3的博客信息
List<Blog> queryBlogForeach(Map map);

sql语句应该为:

select * from blog where id in (1,2,3);

或者

select * from blog where (id= 1 or id = 2 or id =3)

等等…

但是世界有这么简单就好了,下面用freach来实现上面的两个sql语句,记得对比下foreach里面的标签的含义

  • 第一个sql ------ select * from flog where id in (1,2,3)
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
	select * from blog
	where id in
		<foreach collection="ids" item="id" open="(" close=")" separator=",">
			#{id}
		</foreach>
</select>

这个要对比测试来看

@Test
public void queryBlogForeach() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList();
    ids.add(1);
    ids.add(2);
    ids.add(3);
    map.put("ids", ids);
    mapper.queryBlogForeach(map).forEach(System.out::println);
    sqlSession.close();
}
  • 第二个sql—select * from blog where (id= 1 or id = 2 or id =3)
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
	select * from blog
	<where>
		<foreach collection="ids" item="id" open="(" close=")" separator="or">
			id = #{id}
		</foreach>
	</where>
</select>

测试代码 和上面的一样

所以到现在发现什么了吗?

  • collection:指定输入对象中的集合属性 (ids)
  • item:每次遍历生成的对象 (id)
  • open:开始遍历时的拼接字符串 ("(")
  • close:结束时拼接的字符串 (")")
  • separator:遍历对象之间需要拼接的字符串 (“or”) 和 (",")

还有一个小知识点 :

sql片段

  • 有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
  • 提取SQL片段:
<sql id="if-author">
    <if test="title != null">
        adn title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>
  • 引用SQL片段:
<select id="queryBlogIf" parameterType="map" resultType="blog">
	select * from blog
   <where>
       <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
       <include refid="if-author"></include>
       <!-- 在这里还可以引用其他的 sql 片段 -->
   </where>
</select>

注意:

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

  • 在 sql 片段中不要包括 where

小结 :
其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它的技巧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值