当前位置: 首页 > news >正文

Mybatis06-动态SQL

动态SQL

1.什么是动态SQL

什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.

类似JSTL标签

官网描述:
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

我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。

那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

2.环境搭建

  1. 新建一个数据库表: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=utf8;
  1. 创建Mybatis基础工程

  2. IDutil工具类

  3. 实体类编写 【注意set方法作用】

注意:Date类为java.util.Date,不是java.sql.Date

import java.util.Date;public class Blog {private String id;private String title;private String author;private Date createTime;private int views;//set,get....
}
  1. 编写Mapper接口及xml文件
public interface BlogMapper {
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.mapper.BlogMapper"></mapper>
  1. mybatis核心配置文件,下划线驼峰自动转换
<settings><setting name="mapUnderscoreToCamelCase" value="true"/><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--注册Mapper.xml-->
<mappers><mapper resource="com/study/dao/BlogMapper.xml"/>
</mappers>
  1. 插入初始数据

编写接口

//新增一个博客
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>

初始化博客方法

import com.study.dao.BlogMapper;
import com.study.pojo.Blog;
import com.study.utils.IDUtil;
import com.study.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.Date;public class MyTest {@Testpublic void addInitBlog(){SqlSession session = MybatisUtils.getSqlSession();BlogMapper mapper = session.getMapper(BlogMapper.class);Blog blog = new Blog();blog.setId(IDUtil.genId());blog.setTitle("Mybatis如此简单");blog.setAuthor("狂神说");blog.setCreateTime(new Date());blog.setViews(9999);mapper.addBlog(blog);blog.setId(IDUtil.genId());blog.setTitle("Java如此简单");mapper.addBlog(blog);blog.setId(IDUtil.genId());blog.setTitle("Spring如此简单");mapper.addBlog(blog);blog.setId(IDUtil.genId());blog.setTitle("微服务如此简单");mapper.addBlog(blog);session.close();}
}

初始化数据完毕!

3.if标签

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

可以实现按不同列搜索的功能(类似方法重载实现的效果)

  1. BlogMapper

    List<Blog> queryBlogIF(Map map);
    
  2. BlogMapper.xml

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

    这条语句提供了可选的查找文本功能。如果不传入 “title”和“author”,那么所有BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符);如果传入了 “author” 参数,那么就会对 “author” 一列进行查找并返回对应的 BLOG 结果;如果都传,也返回相应的结果

  3. 测试

    @Test
    public void queryBlog(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);Map map=new HashMap();map.put("title","Mybatis如此简单");//        map.put("author","狂神说");List<Blog> blogList = mapper.queryBlogIF(map);for (Blog blog : blogList) {System.out.println(blog);}sqlSession.close();
    }
    

4.trim,where,set

where
  • where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 关键字。
  • 若子句的开头为 “AND” 或 “OR”,where 元素也会视情况将它们去除或保留。
  1. BlogMapper.xml

    <select id="queryBlogIF" parameterType="map"><!--        select * from mybatis.blog where 1=1--><!--        <if test="title != null">--><!--            and title=#{title}--><!--        </if>--><!--        <if test="author != null">--><!--            and author=#{author}--><!--        </if>--><!--为什么需要1=1--><!--如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:SELECT * FROM BLOG WHERE 这会导致查询失败--><!--如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:SELECT * FROM BLOG WHERE AND title = ‘someTitle’ 这个查询也会失败。-->select * from mybatis.blog where<!--        <if test="title != null">--><!--            title=#{title}--><!--        </if>--><!--        <if test="author != null">--><!--            and author=#{author}--><!--        </if>--><!--如何不使用where 1=1-->select * from mybatis.blog<where><if test="title != null">title=#{title}</if><if test="author != null">and author=#{author}</if></where>
    </select>
    
  2. 测试代码同上

set

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

  1. BlogMapper

    int updateBlog(Map map);
    
  2. BlogMapper.xml

    <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>
    
  3. 测试

    @Test
    public void updateBlog(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);Map map=new HashMap();map.put("title","Mybatis如此简单2");map.put("author","狂神说");map.put("id","5482dbf65d264012833e78b74e9fd95b");mapper.updateBlog(map);sqlSession.close();
    }
    

只传title,运行正常

只传author,运行正常

传title和author,运行正常

不传titl和author,报错

trim
<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>

参数说明

  1. prefix:给 trim 标签内 sql 语句加上前缀

  2. suffix:给 trim 标签内 sql 语句加上后缀

  3. prefixOverrides:去除多余的前缀内容,如:prefixOverrides=“OR”,去除 trim 标签内 sql 语句多余的前缀 “OR”

  4. suffixOverrides:去除多余的后缀内容,如:suffixOverrides=“,”,去除 trim 标签内 sql 语句多余的后缀 “,”

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

你可以通过使用trim元素来达到中同样的效果:

<trim prefix="SET" suffixOverrides=",">...
</trim>

注意,我们覆盖了后缀值设置,并且自定义了前缀值。

choose、when、otherwise

类似与switch…case…default

  1. BlogMapper

    List<Blog> queryBlogChoose(Map map);
    
  2. BlogMapper.xml

    <select id="queryBlogChoose" parameterType="map" resultType="blog">select * from mybatis.blog<choose><when test="title != null">title=#{title}</when><when test="author != null">author=#{author}</when><otherwise>and views=#{views}</otherwise></choose>
    </select>
    
  3. 测试

    @Test
    public void queryBlogChoose(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);Map map=new HashMap();//        map.put("title","Mybatis如此简单");//        map.put("author","狂神说");map.put("views",9999);List<Blog> blogList = mapper.queryBlogChoose(map);for (Blog blog : blogList) {System.out.println(blog);}sqlSession.close();
    }
    

    不传参数时,正常运行

    传title和author时,正常运行

    传author时,正常运行

foreach

将blog表中的id改为1,2,3,4

  1. BlogMapper

    //查询1,2,3号记录的博客
    List<Blog> queryBlogForeach(Map map);
    
  2. BlogMapper.xml

    <!-- select * from blog where 1=1 and (id=1 or id=2 or id=3)-->
    <select id="queryBlogForeach" parameterType="map" resultType="blog">select * from blog<where><!--我们现在传递一个万能的map,map中存在一个集合--><foreach collection="ids" item="id" open="and (" close=")" separator="or">id=#{id}</foreach></where>
    </select>
    
  3. 测试

    @Test
    public void queryBlogForeach(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);Map map=new HashMap();ArrayList<Integer> ids = new ArrayList<>();ids.add(1);ids.add(2);ids.add(3);map.put("ids",ids);mapper.queryBlogForeach(map);sqlSession.close();
    }
    
SQL片段

将需要重复编写的sql片段提取出来方便复用

  1. 使用sql标签抽取出重复sql片段:<sql id="sql片段id名">

        <sql id="if-title-author"><if test="title != null">title=#{title},</if><if test="author != null">author=#{author}</if></sql>
    
  2. 在需要使用的地方使用include标签引用即可:<include refid="sql片段id名">

    <select id="queryBlogIF" parameterType="map" resultType="com.study.pojo.Blog">select * from mybatis.blog<where><include refid="if-title-author"/></where>
    </select>
    

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的语法格式,去排列组合就可以了。

建议:先在MYSQL中写出完整的SQL再对应的去修改成动态SQL实现

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

相关文章:

Mybatis06-动态SQL

动态SQL 1.什么是动态SQL 什么是动态SQL&#xff1a;动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句. 类似JSTL标签 官网描述&#xff1a; MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验&#xff0c;你就能体会到根据不同条件拼接…...

26-LINUX--I/O复用-select

一.I/O复用概述 /O复用使得多个程序能够同时监听多个文件描述符&#xff0c;对提高程序的性能有很大帮助。以下情况适用于I/O复用技术&#xff1a; ◼ TCP 服务器同时要处理监听套接字和连接套接字。 ◼ 服务器要同时处理 TCP 请求和 UDP 请求。 ◼ 程序要同时处理多个套接…...

spring源码解析-(2)Bean的包扫描

包扫描的过程 测试代码&#xff1a; // 扫描指定包下的所有类 BeanDefinitionRegistry registry new SimpleBeanDefinitionRegistry(); // 扫描指定包下的所有类 ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(registry); scanner.scan(&quo…...

Java 数学计算 - Random类

在Java中&#xff0c;Random类用于生成伪随机数。这个类在java.util包中&#xff0c;你可以使用它来生成整数、浮点数等不同类型的随机数。以下是关于Random类的一些学习笔记和示例。 1. 创建Random对象 首先&#xff0c;你需要创建一个Random对象。默认情况下&#xff0c;如…...

Ubuntu22.04之解决:无法关机和重启问题(二百四十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

大学数字媒体艺术设计网页设计试题及答案,分享几个实用搜题和学习工具 #媒体#职场发展

现在读书可不像小时候&#xff0c;以前想要校对试题答案&#xff0c;都得找到对应的纸质版答案查看&#xff0c;而且有的还只有答案&#xff0c;没有解析&#xff0c;无法弄清楚答案的由来。但是现在不一样了&#xff0c;现在我们可以通过搜题软件&#xff0c;寻找试题的答案&a…...

【ArcGIS微课1000例】0119:TIFF与grid格式互相转换

文章目录 一、任务描述二、tiff转grid三、grid转tif四、注意事项一、任务描述 地理栅格数据常用TIFF格式和GRID格式进行存储。TIFF格式的栅格数据常以单文件形式存储,不仅存储有R、G、B三波段的像素值,还保存有地理坐标信息。GRID格式的栅格数据常以多文件的形式进行存储,且…...

B3870 [GESP202309 四级] 变长编码

[GESP202309 四级] 变长编码 题目描述 小明刚刚学习了三种整数编码方式&#xff1a;原码、反码、补码&#xff0c;并了解到计算机存储整数通常使用补码。但他总是觉得&#xff0c;生活中很少用到 2 31 − 1 2^{31}-1 231−1 这么大的数&#xff0c;生活中常用的 0 ∼ 100 0…...

WordPress网站更换域名后如何重新激活elementor

在创建WordPress网站时&#xff0c;我们常常需要更改域名。但是&#xff0c;在更换域名后&#xff0c;你可能会遇到一个问题&#xff1a;WordPress后台中的Elementor插件授权状态会显示为不匹配。这时&#xff0c;就需要重新激活Elementor插件的授权。下面我会详细说明如何操作…...

linux cron 执行url

linux cron 执行url 在Linux中&#xff0c;你可以使用curl或wget来执行URL。如果你想要定期执行这个操作&#xff0c;可以使用cron来设置定时任务。 以下是一个使用curl在cron中执行URL的例子&#xff1a; 打开终端。 输入 crontab -e 命令来编辑你的cron作业。 添加一个新…...

压缩视频在线压缩网站,压缩视频在线压缩工具软件

在数字化时代&#xff0c;视频成为了人们记录和分享生活的重要载体。然而&#xff0c;视频文件一般都非常大&#xff0c;这不仅占据了大量的存储空间&#xff0c;也给视频的传输和分享带来了不便。因此&#xff0c;压缩视频成为了许多人必须掌握的技能。本文将详细介绍如何压缩…...

linux经典例题编程

编写Shell脚本&#xff0c;计算1~100的和 首先vi 1.sh,创建一个名为1.sh的脚本&#xff0c;然后赋予这个脚本权限&#xff0c;使用命令chmod 755 1.sh&#xff0c;然后就可以在脚本中写程序&#xff0c;然后运行。 shell脚本内容 运行结果&#xff1a; 编写Shell脚本&#xf…...

二叉树的实现(初阶数据结构)

1.二叉树的概念及结构 1.1 概念 一棵二叉树是结点的一个有限集合&#xff0c;该集合&#xff1a; 1.或者为空 2.由一个根结点加上两棵别称为左子树和右子树的二叉树组成 从上图可以看出&#xff1a; 1.二叉树不存在度大于2的结点 2.二叉树的子树有左右之分&#xff0c;次序不能…...

C++笔试强训day41

目录 1.棋子翻转 2.宵暗的妖怪 3.过桥 1.棋子翻转 链接https://www.nowcoder.com/practice/a8c89dc768c84ec29cbf9ca065e3f6b4?tpId128&tqId33769&ru/exam/oj &#xff08;简单题&#xff09;对题意进行简单模拟即可&#xff1a; class Solution { public:int dx[…...

【JavaScript】内置对象 - 字符串对象 ⑤ ( 判断对象中是否有某个属性 | 统计字符串中每个字符出现的次数 )

文章目录 一、判断对象中是否有某个属性1、获取对象属性2、判定对象是否有某个属性 二、统计字符串中每个字符出现的次数1、算法分析2、代码示例 String 字符串对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String 一、判…...

Linux环境下测试服务器的DDR5内存性能

要在Linux环境下测试服务器的DDR5内存性能&#xff0c;可以采用以下几种方法和工具&#xff1a; ### 测试原理 内存性能测试主要关注以下几个关键指标&#xff1a; - **带宽**&#xff1a;内存每秒能传输的数据量。 - **延迟**&#xff1a;内存访问请求从发出到完成所需的时间…...

19、matlab信号预处理中的中值滤波(medfilt1()函数)和萨维茨基-戈雷滤波滤(sgolayfilt()函数)

1、中值滤波&#xff1a;medfilt1()函数 说明&#xff1a;一维中值滤波 1&#xff09;语法 语法1&#xff1a;y medfilt1(x) 将输入向量x应用3阶一维中值滤波器。 语法2&#xff1a;y medfilt1(x,n) 将一个n阶一维中值滤波器应用于x。 语法3&#xff1a;y medfilt1(x,n…...

Scala 练习一 将Mysql表数据导入HBase

Scala 练习一 将Mysql表数据导入HBase 续第一篇&#xff1a;Java代码将Mysql表数据导入HBase表 源码仓库地址&#xff1a;https://gitee.com/leaf-domain/data-to-hbase 一、整体介绍二、依赖三、测试结果四、源码 一、整体介绍 HBase特质 连接HBase, 创建HBase执行对象 初始化…...

前端工程化:基于Vue.js 3.0的设计与实践

这里写目录标题 《前端工程化&#xff1a;基于Vue.js 3.0的设计与实践》书籍引言本书概述主要内容作者简介为什么选择这本书&#xff1f;结语 《前端工程化&#xff1a;基于Vue.js 3.0的设计与实践》书籍 够买连接—>https://item.jd.com/13952512.html 引言 在前端技术日…...

Linux☞进程控制

在终端执行命令时&#xff0c;Linux会建立进程&#xff0c;程序执行完&#xff0c;进程会被终止&#xff1b;Linux是一个多任务的OS,允许多个进程并发运行&#xff1b; Linxu中启动进程的两种途径&#xff1a; ①手动启动(前台进程(命令gedit)...后台进程(命令‘&’)) ②…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...