Mybatis学习笔记来自B站狂神说Java Mybatis系列视频~
视频链接:https://www.bilibili.com/video/BV1NE411Q7Nx
纯个人手打,可能会有错误,欢迎指正交流探讨~
个人邮箱:460168087@qq.com
11、动态SQL
- 什么是动态SQL:动态SQL指根据不同的查询条件,生成不同的sql语句。
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
-------------------------------
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
-------------------------------
- 使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。
环境搭建
-
新建mysql数据库表
CREATE TABLE `blog` ( `id` varchar(50) NOT NULL COMMENT '博客id', `title` varchar(100) NOT NULL COMMENT '博客标题', `author` varchar(30) NOT NULL COMMENT '博客作者', `create_time` datetime NOT NULL COMMENT '创建时间', `views` int(30) NOT NULL COMMENT '浏览量' ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-
IDutils工具类
package com.gang.utils; import java.util.UUID; public class IDutils { //用于生成唯一的UUID,使blog的各id均唯一 public static String genId(){ return UUID.randomUUID().toString().replaceAll("-",""); } }
-
实体类编写
package com.gang.pojo; import lombok.Data; import java.util.Date; @Data public class Blog { private String id; private String title; private String author; private Date createtime; private int views; }
-
BlogMapper接口与BlogMapper.xml编写
public interface BlogMapper { }
<?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.gang.mapper.BlogMapper"> </mapper>
-
Mybatis-config.xml核心配置文件中,开启下划线驼峰自动转换,注册Mapper
<settings> <!--开启驼峰转换--> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <mappers> <mapper class="com.gang.mapper.BlogMapper"/> </mappers>
-
插入数据
//新增一个blog public int addBlog(Blog blog);
<insert id="addBlog" parameterType="blog"> insert into blog (id, title, author, create_time, views) values (#{id},#{title},#{author},#{createtime},#{views}); </insert>
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDutils.genId()); blog.setTitle("Mybatis如此简单"); blog.setAuthor("狂神说"); blog.setCreatetime(new Date()); blog.setViews(9999); mapper.addBlog(blog); blog.setId(IDutils.genId()); blog.setTitle("Java如此简单"); mapper.addBlog(blog); blog.setId(IDutils.genId()); blog.setTitle("Spring如此简单"); mapper.addBlog(blog); blog.setId(IDutils.genId()); blog.setTitle("微服务如此简单"); mapper.addBlog(blog); sqlSession.commit();//增删改千万别忘记了提交事务 sqlSession.close(); }
环境搭建完毕!
If与Where
需求:当title与author不为空时,根据title or author or两个一起来查询;若两者都为空,查询整张表;只给title或者author,或者两个都不给时,仍能实现查询。
-
接口类编写
public List<Blog> queryBlogIf(Map map);
-
xml编写
<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> </where> </select>
-
测试
@Test public void test1(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","微服务如此简单"); map.put("author","狂神说"); List<Blog> blogs = mapper.queryBlogIf(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。在实际写SQL语句时,使用“where”标签替代where可以有效的避免一些错误。
Set
-
接口类编写
public int updateBlogset(Map map);
-
xml编写
<!--注意set是用的逗号隔开--> <update id="updateBlogset" parameterType="map" > update blog <set> <if test="title != null"> title=#{title}, </if> <if test="author != null"> author =#{author} </if> </set> where id=#{id}; </update>
-
测试
@Test public void test2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","微服务如此简单2"); map.put("author","狂神说2"); map.put("id","917838472cda44b683ad7dfa30f1d639"); mapper.updateBlogset(map); sqlSession.commit(); sqlSession.close(); }
- set是用的逗号隔开
Choose
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句。只选择一个满足的条件!
-
接口类编写
public List<Blog> queryBlogchoose(Map map);
-
xml编写
<select id="queryBlogchoose" parameterType="map" resultType="blog"> select * from blog <where> <choose> <when test="title !=null"> title=#{title} </when> <when test="author!=null"> author=#{author} </when> <otherwise> and views=#{views} </otherwise> </choose> </where> </select>
-
测试
@Test public void test3(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","微服务如此简单2"); map.put("author","狂神说2"); map.put("views",9999); List<Blog> blogs = mapper.queryBlogchoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
SQL片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
- 提取SQL片段,用sql标签,并给该片段取个id
<sql id="if-title-author">
<if test="title != null">
title=#{title}
</if>
<if test="author != null">
and author =#{author}
</if>
</sql>
- 引用SQL片段,用include标签,并输入对应的片段id
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="if-title-author"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</where>
</select>
注意:
- 最好基于单表来定义sql片段,提高片段的可复用性。
- 在sql片段中不要包括where
Foreach[不常用]
-
接口类编写
List<Blog> queryBlogForeach(Map map);
-
xml编写
<select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <where> <!-- collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 separator:遍历对象之间需要拼接的字符串 select * from blog 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>
-
测试
@Test public void testQueryBlogForeach(){ SqlSession session = MybatisUtils.getSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); HashMap map = new HashMap(); List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(2); ids.add(3); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); System.out.println(blogs); session.close(); }
小结:其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它的技巧。