MyBatis中动态sql的实现方法示例
作者:技术小能手 发布时间:2022-08-26 06:02:31
1. 动态sql
动态sql是mybatis中的一个核心,什么是动态sql?
动态sql即对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
MyBatis的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。有些时候,SQL语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息。使用Oracle的序列、mySQL的函数生成Id。这时我们可以使用动态SQL。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
MyBatis中用于实现动态SQL的元素主要有:
1、if和where
2、choose(when,otherwise)
3、trim
4、set
5、foreach
就拿上一篇博文中对用户的综合查询一例来说:
select * from user where user.sex = #{user.sex} and user.username like '%${user.username}%'
假如这个user是null咋整?或者user.sex或者user.username为null呢?所以更严谨的做法应该是在执行这个语句之前要先进行判断才对,确保都不为空,那么我再去查询。这就涉及到了mybatis中的动态sql了。
在mybatis中,动态sql可以使用标签来表示,这很类似于jstl表达式,我们可以将上面的sql语句改成动态sql,如下:
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User">
select * from user <!-- where可以自动去掉条件中的第一个and -->
<where>
<if test="user!=null">
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex} </if>
<if test="user.username!=null and user.username!=''">
and user.username like '%${user.username}%' </if>
</if>
</where>
</select>
上面的代码很好理解,主要就是加了一些判断,条件不为空,才进行查询条件的拼接,让mybatis动态的去执行。那么在测试代码中,我们可以故意的将user.sex不赋初值,就可以看到查询的结果是不一样的。
2. sql片段
那么现在还有个问题,如果好几个statement都需要这样做,而且动态sql部分都一样,这就会导致一些代码的重复,所以如果遇到这种情况,我们就应该抽取,动态sql也可以抽取,我们可以将动态的这部分sql抽取成sql片段,然后在具体的statement中引用进来即可。如下:
<sql id="query_user_where">
<if test="user!=null">
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex} </if>
<if test="user.username!=null and user.username!=''">
and user.username like '%${user.username}%' </if>
</if>
</sql>
id是给该sql片段起个名字而已,内部就是上面的where动态部分,然后我们将上面原来的动态部分改成对这个sql片段的引用,如下:
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User">
select * from user <where>
<!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要在前面加上namespace -->
<include refid="query_user_where"></include>
<!-- 还可以引用其他sql片段 -->
</where>
</select>
3. foreach
还有个问题:如果我们要向sql传递数组或List该咋整呢?mybatis使用的是foreach解析。为了模拟这个场景,我们将上面的查询改成多个id查询,有两种查询方式:
SELECT * FROM USER WHERE id=1 OR id=12 OR id=17SELECT * FROM USER WHERE id IN(1,12,17)
首先有一点很明确,既然要使用多个id进行查询,那么多个id肯定要作为参数传进来,所以存储多个id的List需要放到UserQueryVo中作为一个属性,这点很好理解,所以我们先在UserQueryVo中增加这个属性:
//传入多个id
private List<Integer> ids;
然后我们修改UserMapper.xml中的sql片段(还是写在sql片段中),如下:
<sql id="query_user_where">
<if test="user!=null">
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex} </if>
<if test="user.username!=null and user.username!=''">
and user.username like '%${user.username}%' </if>
</if>
<if test="ids!=null">
<!-- 使用右边的sql拼接:AND (id=1 OR id=12 OR id=17) -->
<foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR">
id=#{user_id}
</foreach>
</if>
</sql>
下面简单介绍一下这个foreach中相关属性的作用:
collection:指定输入对象中的集合属性,这里就是这个ids。 item:表示每个遍历生成的对象,自己起个名儿,在foreach体中使用。 open:开始遍历时拼接的sql串。 close:结束遍历时拼接的sql串。 separator:遍历的两个对象中需要拼接的sql串。
我们测试一下,然后看下控制台打印出来的sql就很容易理解了。测试程序:
@Testpublic void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
User user = new User();
//由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
user.setSex("男");
user.setUsername("倪升武");
//传入多个id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(12);
ids.add(17);
userQueryVo.setIds(ids);
userQueryVo.setUser(user);
//调用userMapper的方法
List<User> list = userMapper.findUserList(userQueryVo);
System.out.println(list);}
看下控制台打印出的sql:
select * from user WHERE user.sex = ? and user.username like '%倪升武%' AND ( id=? OR id=? OR id=? )
注意一个细节:在mybatis中,如果输入的是Integer或者int类型的0,上面那个if判断标签返回的是false,也就是说,即使非空非'',也不会拼接标签体中的sql。
所以mybatis自动的将多个id拼接到了sql中。那么另外一个sql的实现就不再赘述了,跟上面的一样,唯一不同的就是sql片段部分,如下:
<!-- 使用右边的sql拼接:AND id IN(1,12,17) -->
<foreach collection="ids" item="user_id" open="AND id IN(" close=")" separator=",">
#{user_id}</foreach>
来源:https://yq.aliyun.com/articles/667279


猜你喜欢
- ForkJoin简介Fork/Join框架是Java 7提供的一种用于并行执行任务的框架,它将大任务分解为若干个小任务,并行执行这些小任务,
- 本文实例讲述了Java中对象的比较操作。分享给大家供大家参考,具体如下:一 点睛在Java中,有两种方式可用于对象间的比较:利用"
- 如果我们遇到把excel表格中的数据导入到数据库,首先我们要做的是:将excel中的数据先读取出来。因此,今天就给大家分享一个读取Excel
- 前言本文主要给大家介绍了关于Spring中@Scheduled和HttpClient的坑,分享出来供大家参考学习,下面话不多说了,来一起看看
- 概述用Time和Calendar获取系统当前时间(年月日时分秒周几)效果图源码:import android.app.Activity; i
- maven打包时候修改包名称带上git版本号和打包时间使用 maven 插件 git-commit-id-plugin 可以获取项目的git
- 前言:在Java项目中,有两个主要的构建系统:Gradle和Maven。构建系统主要管理潜在的复杂依赖关系并正确编译项目。还可以将已编译的项
- 前两天发现 idea 终于更新了2020.1版本,新增了好多的特性,这里不介绍,主要写一下中文插件的安装首先下载新版 安装包 https:/
- 本文较为详细的分析了Java中对象的销毁方法。分享给大家供大家参考。具体分析如下:Java中的基本数据类型变量和对象的名称引用变量如定义在方
- gradle下载慢问题解决方法下载之后自行安装 ps:就是手动更新。官网地址和gradle各版本下载地址:官网:http://gradle.
- 本文实例讲述了Android开发实现Files文件读取解析功能。分享给大家供大家参考,具体如下:package com.example.fi
- 时间轮关于时间轮的介绍,网上有很多,这里就不重复了核心思想一个环形数组存储时间轮的所有槽(看你的手表),每个槽对应当前时间轮的最小精度超过当
- 一、什么是IOC1)控制反转,把创建对象和对象的调用过程交给Spring 管理。2)使用IOC的目的,为了降低耦合度。二、IOC的底层原理X
- IM SDK API 概述 https://cloud.tencent.com/document/product/269/33543///
- 一.概述先给大家看一下效果图:点击中间的显示弹框按钮,从底部弹出来一个对话框,用户可以点击拍照或者从相册选择进行相应的操作,下面看看怎么实现
- 本文实例为大家分享了SSM实现学生管理系统的具体代码,供大家参考,具体内容如下概述基于Spring + Spring MVC 的学生管理系统
- Quartz是一款开源的定时任务调度框架,Quartz的官网是:http://www.quartz-s
- 本文实例讲述了C#画笔Pen绘制光滑模式曲线的方法。分享给大家供大家参考。具体实现方法如下:using System;using Syste
- 问题springboot 集成springcloud时常常由于版本问题而报错,如下:com.sun.jersey.api.client.Cl
- Android实现TextView超链接一共有五种方式:推荐第四种、第五种1. 直接在xml文件中配置autoLink属性(简单易用,效果单