文章目录
什么是动态SQL?
在MyBatis中可以存在动态SQL,那么什么是动态SQL呢?
动态SQL就是指根据不同的条件生成不同的SQL语句
可能还有的小伙伴不理解,那么我就举几个例子,大家一看就懂了~
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。
在 MyBatis 之前的版本中,有很多元素需要花时间了解。
MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。
MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
if
choose (when, otherwise)
trim (where, set)
foreach
搭建环境
首先我们先创建一个基础工程
1.创建一个数据库并创建一张表
CREATE DATABASE `mybatis`;
USE `mybatis`;
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
2.编写实体类
每一个数据库的表必定对应一个实体类
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;
}
注意:这里的日期的字段名create_time
和属性名createTime
不一样,这里就要说一下了
因为Java的命名规范是驼峰式命名,而Mysql中是用下划线来分割两个单词的,所以我们要遵守规范来!
那么这里会有小伙伴说了,这个不一样怎么办,会不会报错呢?
当然,人家官方早就解决了这个问题,怎么做嘞!
我们只需要在MyBatis的核心配置文件MyBatis_config.xml中添加以下配置就好啦~
<settings>
<!--这个就会自动将下划线转换成驼峰了-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3.编写配置文件
配置文件怎么操作具体请参考我的上一篇博客这里就不再详细解释了
这里在utils包下新建一个IDUtils类,用来生成随机的id,因为在实际开发中,我们不可能用1,2,3,4这些简单的数字作为id,id一般都是随机生成的很长的一大串。
package com.gang.utils;
import java.util.UUID;
public class IDUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
}
4.编写实体类对应Mapper接口和对应的Mapper.XML文件
BlogMapper接口
package com.gang.mapper;
import com.gang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
//里面写方法
int addBlog(Blog blog);
}
BlogMapper.XML连接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">
<!-- 原来我们都是编写具体的执行sql -->
<mapper namespace="com.gang.mapper.BlogMapper">
<!--这里写具体的SQL语句-->
<insert id="addBlog" parameterType="Blog">
insert into blog(id,title,author,create_time,views)
values (#{id},#{title},#{author},#{createDate},#{views})
</insert>
</mapper>
5.建一个测试类
注意:我们这里使用了@Test这个注解,它可以不用写主方法,就能运行,用来测试代码很方便,我们要使用它,有一个前提,就是要导入junit依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
怎么导入依赖我上一篇博客也有哦~
package com.gang.mapper;
import com.gang.pojo.Blog;
import com.gang.utils.IDUtils;
import com.gang.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class BlogMapperTest {
//我们先往表里添加点数据
@Test
public void testAddBlog(){
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
for (int i = 0; i < 5; i++) {
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setAuthor("范孟钢");
blog.setCreateDate(new Date());
blog.setTitle("MyBatis入门技巧");
blog.setViews(9999);
mapper.addBlog(blog);
}
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setAuthor("大超");
blog.setCreateDate(new Date());
blog.setTitle("Javaweb入门技巧");
blog.setViews(9999);
mapper.addBlog(blog);
Blog blog1 = new Blog();
blog1.setId(IDUtils.getId());
blog1.setAuthor("范孟钢");
blog1.setCreateDate(new Date());
blog1.setTitle("Mysql入门技巧");
blog1.setViews(9999);
mapper.addBlog(blog1);
Blog blog2 = new Blog();
blog2.setId(IDUtils.getId());
blog2.setAuthor("大超");
blog2.setCreateDate(new Date());
blog2.setTitle("微服务入门技巧");
blog2.setViews(9999);
mapper.addBlog(blog2);
Blog blog3 = new Blog();
blog3.setId(IDUtils.getId());
blog3.setAuthor("大超");
blog3.setCreateDate(new Date());
blog3.setTitle("大数据入门技巧");
blog3.setViews(9999);
mapper.addBlog(blog3);
}
//提交事务
session.commit();
}
注意:增删改一定要开启事务!不然会导致程序运行成功了,但是数据库没啥变化!
好,运行程序,这几条数据就被插进去了。
有了数据之后,我们就可以玩一下这个动态SQL了
了解动态SQL
if(带你理解动态SQL)
在接口中编写如下方法(我这里就不写整个类了,太麻烦,没必要,大家能看懂就行)
//通过作者名和博客名来查询,如果作者名为null,则根据博客名来查
//就是说这里的条件是可以做选择的
List<Blog> getBlogByIf(Map map);
//这里使用参数为Map,就是不知道我们要传几个参数,就设为Map,我们想传几个都可以
xml配置文件中执行以下sql语句,是不是和以前写的sql语句有点不一样呢?
<!--
如果我们要拼接where条件,又不希望客户端传来的信息是错误的(比如说传递空值,就是map为空)
这就需要更加智能的where标签了
<where> </where>
如果后面有语句(传入不为空)就会自动加上where 如果后面语句的开头是and或者or,它会自动去掉
if标签表示条件判断
原来的sql : select * from blog
where title = #{title} and author = #{author}
if标签注意后面的and,不要忘了
-->
<select id="getBlogByIf" 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 testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title", "MyBatis入门技巧");
map.put("author", "范孟钢");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看结果
②我们只传入作者这个参数
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//map.put("title", "MyBatis入门技巧");
map.put("author", "范孟钢");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看结果
③我们只传入博客名一个参数
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title", "MyBatis入门技巧");
//map.put("author", "范孟钢");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看结果
④这次我们不传任何参数
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//map.put("title", "MyBatis入门技巧");
//map.put("author", "范孟钢");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看结果
到这里你会发现,我们明明只写了一个SQL语句,为什么它会根据我们输入的参数不同而去执行不同的SQL语句呢?
所谓的动态SQL,本质还是SQL语句 , 只是我们可以在SQL层面,去执行一个逻辑代码
注意(要想看到这些执行的具体的SQL,就要打开日志,我上篇博客也有)
好了,大家是否已经理解动态SQL了呢?
接下来我们再学学其他的一些标签
trim (where,set)
where标签上面已经讲过了,这里讲一下set标签
好,编写如下方法
在这里插入代码片
编写sql
<!--
set标签重点注意后面的 逗号, 最后一句没有逗号
它会动态前置set关键字,也可以给你智能的去掉逗号
原来的sql: update blog
set title = #{title},author = #{author}
where id = #{id}
-->
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title!=null">
title = #{title},
</if>
<if test="author!=null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
测试方法
①传入id和title
@Test
public void testUpdateSet() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","78f5b3cced7d4a5e92131039f6388d8a");
map.put("title","论一个优秀打野的自我修养");
mapper.updateBlog(map);
session.commit();
}
看结果
②传入id和作者
@Test
public void testUpdateSet() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","78f5b3cced7d4a5e92131039f6388d8a");
//map.put("title","论一个优秀打野的自我修养");
map.put("author","韩信");
mapper.updateBlog(map);
session.commit();
}
看结果
③id和其他两个都传
@Test
public void testUpdateSet() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","78f5b3cced7d4a5e92131039f6388d8a");
map.put("title","一只野怪的内心独白");
map.put("author","蓝buff");
mapper.updateBlog(map);
session.commit();
}
看结果
set和where的底层都是一个标签trim
这个是where标签的真面目
<trim prefix="WHERE" prefixOverrides="AND|OR">
...
</trim>
前面的查询sql可以改为这个
<select id="getBlogByIf" resultType="Blog" parameterType="map">
select * from blog
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="title!=null">
title = #{title}
</if>
<if test="author!=null">
and author = #{author}
</if>
</trim>
</select>
这个是set标签的原型
<trim prefix="set" suffixOverrides=",">
...
</trim>
前面的更新sql可以改为这个
<update id="updateBlog" parameterType="map">
update blog
<trim prefix="set" suffixOverrides=",">
<if test="title!=null">
title = #{title},
</if>
<if test="author!=null">
author = #{author}
</if>
</trim>
where id = #{id}
</update>
choose (when, otherwise)
接口方法
//查询博客,有一个条件满足即可
List<Blog> getBlogByChoose(Map map);
SQL语句
<!--choose好比Java中的switch标签,只能选择一个-->
<select id="getBlogByChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<choose>
<when test="title!=null">
title = #{title}
</when>
<when test="author!=null">
and author = #{author}
</when>
<otherwise>
<!--什么都不传就走这个,相当于defalut-->
and views = #{views}
</otherwise>
</choose>
</where>
</select>
测试方法
①啥都不传
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
②传一个作者author
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("author","范孟钢");
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
③传一个博客名title
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title","一只野怪的内心独白");
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
④两个都传
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title","一只野怪的内心独白");
map.put("author","范孟钢");
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
注意看了
怎么和第三种情况一样呢?说明choose标签只能进一个条件,就和Java中switch语句一样,进了一个条件后面的都不看了!
Foreach
写如下接口方法
List<Blog> getBlogByForeach(Map map);
SQL语句
<!--sql() 子查询 where in (1,2,3)
collection中是传进来的参数集合
item是collection中参数的遍历,就拿到每一个,并且可以直接在foreach标签中使用
他是这样拼接的 select * from blog where and (id=1 or id=2 or id=3)
open是开头 separator是分割的 在每个中间 close是结束
-->
<select id="getBlogByForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
测试方法
@Test
public void testForEach() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String,List> map = new HashMap<String, List>();
List<String> ids = new ArrayList<String>();
ids.add("78f5b3cced7d4a5e92131039f6388d8a");
ids.add("151f3db24ba24a4f8092849a1e221da0");
ids.add("80a7578f55c5403c8986bf409b3f8d51");
map.put("ids",ids);
List<Blog> blogByChoose = mapper.getBlogByForeach(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
说了这么多
动态SQL就是用这些标签在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
不知道还有小伙伴没看明白嘛 挥挥~