12.动态SQL
12.动态SQL
什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句
利用动态SQL这一特性可以彻底摆脱这种痛苦
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
12.1搭建环境
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
创建一个基础工程
- 导包
- 编写核心配置文件
- 编写实体类
注意:java中创建实体类中的时间属性需选择.util,选择.sql不生效
@Data public class Blog { private int id; private String title; private String author; private Date createTime;//属性名和字段名不一致 private int views; }
如何解决属性名和字段名不一致:
在核心配置文件的Setting方法里加入如下代码:
<settings> <!--开启驼峰命名转换--> <setting name="mapUnderscoreToCamelCase" value="true "/> </settings>
- 编写工厂类(utils—sqlSessionFactory)
- 编写实体类对应的Mapper接口和Mapper.xml文件
IF标签
BlogMapper
//查询博客 List<Blog> queryBlogIF(Map map);
BlogMapper.xml
<mapper namespace="com.itxiaofei.dao.BlogMapper"> <insert id="addBlog" parameterType="blog"> insert into mybatis.blog (id, title, author, create_time, views) values(#{id},#{title}, #{author}, #{createTime}, #{views}); </insert> <!--if标签是固定的格式--> <select id="queryBlogIF" parameterType="map" resultType="blog"> select * from mybatis.blog <!--where 1=1--> <!--不使用where也可以在后面加where1=1,但是不正规--> <where> <if test="title != null"> and title like #{title} </if> <if test="author != null"> and author like #{author} </if> </where> </select> </mapper>
使用where标签的原因:(where 1=1不正规!)
测试:
//测试动态SQL中if @Test public void queryBlogIF(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); /*map.put("title","Java并不难");*/ map.put("author","if小飞"); List<Blog> blogs = mapper.queryBlogIF(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
choose (when, otherwise)标签
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。
1.BlogMapper
List<Blog> queryBlogChoose(Map map)
2.BlogMapper.xml
<select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <choose> <when test="title != null"> and title like #{title} </when> <when test="author != null"> and author like #{author} </when> <otherwise> and views = #{views} </otherwise> </choose> </where> </select>
3.测试
//测试动态SQL中choose (when, otherwise)标签 @Test public void queryBlogChoose(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("views","9999"); /*map.put("title","Java并不难");*/ /*map.put("author","if小飞");*/ List<Blog> blogs = mapper.queryBlogChoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
trim、where、set标签
where标签:(自动去除“AND” 或 “OR”)
<select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <choose> <when test="title != null"> and title like #{title} </when> <when test="author != null"> and author like #{author} </when> <otherwise> and views = #{views} </otherwise> </choose> </where> </select>
set标签:(自动去除逗号)
<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>
set测试:
//测试动态SQL中的set标签 @Test public void updateBlog(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //id后面的参数那么一长串是因为之前加了UUID防止数据太多导致重复 map.put("id","f125088b7dd74826a6b4eddc42132ad4"); map.put("title","Python并不难"); map.put("author","it小飞呀"); mapper.updateBlog(map); sqlSession.close(); }
trim标签:
trim标签你可以理解为是set和where标签的整合
<!--prefix:前缀 ,prefixOverrides:前缀覆盖内容 suffix:后缀 ,suffixOverrides:后缀覆盖内容 --> <trim prefix="" prefixOverrides="" suffix="" suffixOverrides=""> <!--写拼接的sql语句--> </trim>
所谓的动态SQL,本质还是SQL,只是我们可以在SQL层面,去执行一个逻辑代码
Foreach(遍历)
1.编写接口
List<Blog> queryBlogForeach(Map map);
2.Foreach标签的使用
<!--Foreach标签 select * from blog where and(id=1 or id=2 or id=3) 下面Foreach标签的作用就是拼接这段话 我们传递一个万能的map,这个map中可以存在一个集合 --> <select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <where> <foreach collection="ids" item="id" open="and (" close=")" separator="or"> id = #{id} </foreach> </where> </select>
3.测试
//测试动态SQL中的Foreach标签 @Test public void queryBlogForeach(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //我们不知道到底有多少个数据元素的时候,就可使用ArrayList;<>里面放的是:泛型 //<>作用就是确定到底存放什么类型 // 如果知道数据集合有多少个元素,就用数组。 ArrayList<Integer> ids = new ArrayList<Integer>(); //Java Map.put()方法:获取Map集合的所有键名 map.put("ids",ids); ids.add(1); ids.add(2); ids.add(3); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
SQL片段
有些时候,我们可能会将一些公共的部分抽取出来,方便复用
1.使用sql标签抽取公共的部分
<sql id="if-title-author"> <if test="title != null"> and title like #{title} </if> <if test="author != null"> and author like #{author} </if> </sql>
2.在需要使用的地方使用Include标签引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <include refid="if-title-author"></include> </where> </select>
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
建议:
- 先在Mysql中写出完整的SQL,再对应去修改成为我们的动态SQL实现通用即可
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术