什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句
利用动态SQL这一特性可以彻底摆脱JDBC之前拼接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
搭建测试数据库环境
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
创建一个基础工程
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.26version>
dependency>
mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="root"/>
properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<typeAliases>
<package name="com.hang.pojo"/>
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="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper class="com.hang.dao.BlogMapper"/>
mappers>
configuration>
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true"
username=root
password=root
package com.hang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;//属性名和字段名不一致
private int views;
}
这里的id用的String,我们用UUID来生成一个唯一的Id
在utils包下再新建一个工具类:
package com.hang.utils;
import org.junit.Test;
import java.util.UUID;
@SuppressWarnings("all")//镇压警告
public class IDUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");//把-换掉
}
@Test
public void test(){
System.out.println(IDUtils.getId());
System.out.println(IDUtils.getId());
System.out.println(IDUtils.getId());
}
}
package com.hang.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* sqlSessionFactory(构建sqlSession的)
* 定义一个工具类 把资源加载进来 创建一个能执行sql的对象 整个对象可以想象成一个Connection对象
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;//提升作用域
//使用Mybatis第一步:获取sqlSessionFactory对象
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过build把这个流加载进来
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
//我们可以在工具类创建的时候实现自动提交事务! 不用再手动提交了
SqlSession sqlSession = sqlSessionFactory.openSession(true);//会返回一个SqlSession(里面有操作数据库的方法 相当于之前的statement对象)
return sqlSession;
//优化代码
}
}
编写实体类对应的Mapper接口和Mapper.xml文件
Mapper接口:
package com.hang.dao;
import com.hang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
/**
* 插入数据
* @param blog
* @return
*/
int addBlog(Blog blog);
/**
* 查询博客 使用if
* @param map
* @return
*/
List<Blog> queryBlogIF(Map map);
//
List<Blog> queryBlogChoose(Map map);
/**
* 更新博客
* @param map
* @return
*/
int updateBlog(Map map);
}
Mapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hang.dao.BlogMapper">
<insert id="addBlog" parameterType="blog">
insert into mybatis.blog (id,title,author,create_time,views)
values(#{id},#{title},#{author},#{createTime},#{views})
insert>
<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>
<select id="queryBlogChoose" resultType="blog" parameterType="map">
select * from mybatis.blog
<where>
<choose>
<when test="title!=null">
title = #{title}
when>
<when test="author!=null">
and author = #{author}
when>
<otherwise>
and views = #{views}
otherwise>
choose>
where>
select>
<update id="updateBlog" parameterType="map" >
update mybatis.blog
<set>
<if test="title!=null">
title = #{title},
if>
<if test="author!=null">
author = #{author}
if>
set>
where id = #{id}
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
trim>
<trim prefix="" prefixOverrides="" suffix="" suffixOverrides="">
trim>
update>
mapper>
IF
优化
<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>
choose(when,otherwise)
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。
<select id="queryBlogChoose" resultType="blog" parameterType="map">
select * from mybatis.blog
<where>
<choose>
<when test="title!=null">
title = #{title}
when>
<when test="author!=null">
and author = #{author}
when>
<otherwise>
and views = #{views}
otherwise>
choose>
where>
select>
select * from mybatis.blog
<where>
<if test="title != null">
title = #{title}
if>
<if test="author != null">
and author = #{author}
if>
where>
trim(where,set)
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
<update id="updateBlog" 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>
所谓的动态SQL,本质还是SQL语句 , 只是我们可以在SQL层面,去执行一个逻辑代码
if
where,set,choose,when
测试类
import com.hang.dao.BlogMapper;
import com.hang.pojo.Blog;
import com.hang.utils.IDUtils;
import com.hang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
* 既然能用Java插入数据 那也能用Java写数据库的脚本 给别人一个库 把这个东西写在Java里 让别人去跑这个Java文件就行
*/
public class MyTest {
@Test
public void addInitBlog(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setTitle("Mybatis使用如此简单");
blog.setAuthor("wuwuwu");
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);
sqlSession.close();
}
@Test
public void queryBlogIF(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();//通过不同参数实现动态sql效果
map.put("title","Java使用如此简单");
map.put("author","吴哲航");
List<Blog> blogs = mapper.queryBlogIF(map);//map为空也能查
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
/**
* where元素只会在至少有一个子元素的条件返回sql子句的情况下才回去插入where子句,而且,若语句的开头为and或者or where元素会将它们去掉
*/
@Test
public void queryBlogChoose(){
SqlSession sqlSession = MybatisUtils.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();
}
@Test
public void updateBlog(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","Java使用如此简单222");
map.put("author","吴哲航22");
map.put("id","dfe8161b356b417db7b24ea95eb67d3a");
int i = mapper.updateBlog(map);
if (i>0){
System.out.println("更新成功!");
}
sqlSession.close();
}
}