什么是动态SQL: 动态SQL就是根据不同的条件生成不同的SQL语句 利用动态 SQL,可以彻底摆脱这种痛苦
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。 if choose (when, otherwise) trim (where, set) foreach 搭建环境 获取随机的ID Iutils package com.xuyuan.Utils; import java.util.UUID; @SuppressWarnings("all")//抑制警告 public class IDUtils { public static String getId(){ return UUID.randomUUID().toString().replaceAll("-",""); } }新建一个数据库表:blog
字段:id,title,author,create_time,views 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=utf81.创建一个基础工程 导包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> </dependencies>2.编写配置文件 3.编写实体类
package com.xuyuan.Pojo; import lombok.Data; import java.util.Date; @Data public class Blog { private int id; private String title; private String author; private Date createTime; private int views; } 4、编写Mapper接口及xml文件 package com.xuyuan.Dao; public interface BlogMapper { } <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xuyuan.Dao.BlogMapper"> </mapper> 5、mybatis核心配置文件,下划线驼峰自动转换 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!--环境--> <!--引入外部符号--> <properties resource="db.properties"/> <settings> <!--标准的日志工厂--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!-- 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- <setting name="logImpl" value="LOG4J"/>--> </settings> <!--可以给实体类起别名--> <typeAliases> <typeAlias type="com.xuyuan.Pojo.Blog" alias="blog"></typeAlias> </typeAliases> <environments default="development"><!--默认那个环境--> <environment id="development"><!--开发--> <transactionManager type="JDBC"/><!--事务管理--> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${user}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper class="com.xuyuan.Dao.BlogMapper"/> <mapper resource="com/xuyuan/Dao/BlogMapper.xml"/> </mappers> </configuration> 6、插入初始数据 编写接口 //新增一个博客 int addBlog(Blog blog); sql配置文件 <insert id="addBlog" parameterType="blog"> insert into blog (id, title, author, create_time, views) values (#{id},#{title},#{author},#{createTime},#{views}); </insert> 初始化博客方法 import com.xuyuan.Dao.BlogMapper; import com.xuyuan.Pojo.Blog; import com.xuyuan.Utils.IDUtils; import com.xuyuan.Utils.Utils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.Date; public class test { @Test public void addInitBlog(){ SqlSession session = Utils.getSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDUtils.getId()); blog.setTitle("Mybatis如此简单"); blog.setAuthor("狂神说"); blog.setCreateTime(new Date()); blog.setViews(9999); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("Java如此简单"); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("Spring如此简单"); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("微服务如此简单"); mapper.addBlog(blog); session.close(); } }初始化数据完毕!
if 使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分 接口
List<Blog> queryBlogIf(Map map); }xml
<select id="queryBlogIf" parameterType="map" resultType="blog"> select * from mybatis.blog where 1=1 <if test="title!=null"> and title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </select>test
@Test public void queryBlogIf(){ SqlSession sqlSession = Utils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); // map.put("title","Java如此简单"); map.put("author","狂神说"); List<Blog> blogs = mapper.queryBlogIf(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }要不就是重载 多个接口
public interface BlogMapper { int addBlog(Blog blog); //查询博客 List<Blog> queryBlogIf(Map map); List<Blog> queryBlogIf(Map map,sad); //不同查询写不同的Sql就行了 }这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句! Where
<select id="queryBlogIf" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <if test="title!=null"> and title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </where> </select>Set
<update id="updataBlog" parameterType="map"> update mybatis.blog <set> <if test="title !=null"> title=#{title}, </if> <if test="author !=null"> author=#{author} </if> </set> where id=#{id} </update>测试:
@Test public void updataBlog(){ SqlSession sqlSession = Utils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","Java如此简单2"); map.put("id","bb2d9c0e9fdb4e49ae53033deb6acfac"); mapper.updataBlog(map); sqlSession.close(); } } choose语句有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的
switch 语句case <select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from mybatis.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> <!-- where相当于switch otherwise相当于case -->测试:
@Test public void queryBlogIf(){ SqlSession sqlSession = Utils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","Java如此简单"); map.put("author","狂神说"); map.put("views",9999); List<Blog> blogs = mapper.queryBlogChoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }所谓的动态 Sql,本质还是sql语句,只是我们可以在Sql层面,去执行一个逻辑代码 if when set choose when
有时候我们会将一些功能抽取出来,方便复用 1.使用SQL标签抽取公共部分 2.在需要使用的地方使用include标签引用即可
<sql id="title-author"> <if test="title!=null"> and title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </sql> <select id="queryBlogIf" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <include refid="title-author"/> </where> </select>注意事项: 1.最好基于单表来定义SQL片段 2.在提取出来的片段最好不要存在where标签 要不就相当于把下边拿上去了实现不了复用。 Foreach
将数据库中前三个数据的id修改为1,2,3;
需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息 1、编写接口
List<Blog> queryBlogForeach(Map map);2、编写SQL语句
<!-- collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 separator:遍历对象之间需要拼接的字符串 select * from blog where 1=1 and (id=1 or id=2 or id=3) --> <select id="queryBlogForeach" parameterType="map" resultType="blog"> select *from mybatis.blog <where> <foreach collection="ids" item="id" open="and (" close=")" separator="or"> id=#{id} </foreach> </where> </select>3.测试
@Test public void queryBlogForeach(){ SqlSession sqlSession = Utils.getSqlSession(); BlogMapper mapper = sqlSession.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); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); } }小结:其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它的技巧。
动态SQL在开发中大量的使用,一定要熟练掌握!
