MyBatis动态SQL语句

embedded/2024/9/22 17:01:00/

        在实际的操作中,有时候一些查询条件是不确定是否传进来的,特别是在多条件查询的情况下,不一定要把多有的条件都传入。如果在执行一个操作的时候,一个参数没有传递进来,会直接影响查询的结果。MyBatis提供了完美解决这一问题的方案,就是使用动态SQL语句。

        MyBatis的一个强大之处就是拥有动态SQL语句功能,相比较其他的持久化框架为了一个不确定的查询条件,需要编写大量的Java代码,而MyBatis只需要在配置文件中通过几个简单的标签就完美解决了。MyBatis的动态SQL语句提供了if、choose、when、otherwise、foreach等标签,有了这些标签,使得MyBatis在处理不确定条件的问题上变得得心应手。

if语句——选择语句

        很明显,if语句是用来执行一些不确定的查询,用来编写一些不确定是否传递进来的查询条件。假如在查询t_person表的时候,传入两个条件一个是name,另一个是sex,其中sex是一个不确定的参数,要求是当传入sex参数时添加条件的查询,如果没有传入sex参数就不参加查询条件,具体写法如下所示。

<select id="dynamicLoad" parameterType="Person" resultMap="personMap"><bind name="parameter" value="'%' + _parameter.name + '%'"/>select * from t_person where person_name like #{parameter}<if test="sex != null">and person_sex=#{sex}</if>
</select>

        注意此时的parameterType类型为Person,在执行查询的时候需要传递进来一个Person对象,具体的测试代码如下。

java">@Test
public void testDynamic() {SqlSession session = null;try {session = factory.openSession();Person person = new Person();person.setName("a");person.setSex("男");List<Person> persons = session.selectList("com.obj.model.Person.dynamicLoad", per);for(Person per:persons) {System.out.println(per);}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}
}

        此时传入了sex查询条件,具体的执行结果如下所示。

Preparing: select * from t_person where person_name like ? and person_sex=? 
Parameters: %a%(String), 男(String)
Total: 3
Person [id=1, name=aaa, age=20, sex=男, email=aaa@obj.com]
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        通过执行结果可以看到,sex条件参与的查询,而如果没有传入sex属性,执行结果如下所示。

Preparing: select * from t_person where person_name like ? 
Parameters: %a%(String)
Total: 3
Person [id=1, name=aaa, age=20, sex=男, email=aaa@obj.com]
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        很明显,这个时候sex就没有参与查询。

choose、when、otherwise语句——分支判断语句

        遇到需要分支判断的时候,MyBatis提供了分支判断语句。当然了,多个分支判断语句都可以使用if语句来完成,不过有些时候使用多分支还是要更好一些。choose、when、otherwise等语句的使用方法,具体代码如下。

<select id="dynamicLoad" parameterType="Person" resultMap="personMap"><bind name="parameter" value="'%' + _parameter.name + '%'"/>select * from t_person where person_name like #{parameter}<choose><when test="sex != null and age == 0">and person_sex=#{sex}</when><when test="age != 0 and sex == null">and person_age>#{age}</when><when test="sex != null and age != 0">and person_sex=#{sex} and person_age>#{age}</when><otherwise>and person_sex in ('男','女') and person_age>18</otherwise></choose>
</select>

        以上的条件一共有四条,第一如果传入了性别而没有传入年龄,就执行第一条SQL语句;第二如果传入了年龄而没有传入性别,就执行第二条SQL语句;第三如果性别和年龄都传入了,就执行第三条SQL语句;第四如果性别和年龄都没有传入,就执行第四条SQL语句。很明显以上的四条SQL语句只会执行一条,从而更方便的控制了SQL语句的灵活度。在性别和年龄条件都传入的情况下,执行的结果如下所示。

Preparing: select * from t_person where person_name like ? and person_sex=? and person_age>? 
Parameters: %a%(String), 男(String), 20(Integer)
Total: 2
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        在只传入性别,而没有传入年龄的情况下,执行结果如下所示。

Preparing: select * from t_person where person_name like ? and person_sex=? 
Parameters: %a%(String), 男(String)
Total: 3
Person [id=1, name=aaa, age=20, sex=男, email=aaa@obj.com]
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        在只传入年龄,而没有传入性别的情况下,执行结果如下所示。

Preparing: select * from t_person where person_name like ? and person_age>? 
Parameters: %a%(String), 20(Integer)
Total: 2
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        在性别和年龄都没有传入的情况下,执行结果如下所示。

Preparing: select * from t_person where person_name like ? and person_sex in ('男','女') and person_age>18 
Parameters: %a%(String)
Total: 3
Person [id=1, name=aaa, age=20, sex=男, email=aaa@obj.com]
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        通过以上的例子,很好的验证了MyBatis动态SQL功能的强大,使得编程更加灵活。

where、set、trim——逻辑语句

        在讲述新的知识点之前,我们先来看一个问题,代码如下。

<select id="dynamicLoad" parameterType="Person" resultMap="personMap">select * from t_person where <if test="name != null">person_name like "%"#{name}"%"</if><if test="sex != null">and person_sex=#{sex}</if><if test="age > 0">and person_age>#{age}</if>
</select>

        上述的查询操作一共有三个条件判断,如果在执行的时候一个条件都没有传入,最后发出的SQL语句应该是“select * from t_person where”,很明显,这样的SQL语句执行下去肯定是错误的,会抛出“com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException”异常。如果在执行的时候只有第一个条件没有传入进来,其他的条件正常传入,最后的SQL语句应该是“select * from t_person where and person_sex=? and person_age>?”,在where语句之后多了一个and,这样也是错误的。

        因此为了解决上述问题,MyBatis提供了where标签等逻辑语句,我们可以把语句写成这样。

<select id="dynamicLoad"  parameterType="Person" resultMap="personMap">select * from t_person <where><if test="name != null">person_name like "%"#{name}"%"</if><if test="sex != null">and person_sex=#{sex}</if><if test="age > 0">and person_age>#{age}</if></where>
</select>

        这个时候,如果一个条件都没传进来,就不会出现where语句,执行结果如下所示。

Preparing: select * from t_person 
Parameters: 
Total: 6
Person [id=1, name=aaa, age=20, sex=男, email=aaa@obj.com]
Person [id=2, name=bbb, age=20, sex=女, email=bbb@obj.com]
Person [id=3, name=ccc, age=21, sex=男, email=ccc@obj.com]
Person [id=4, name=ddd, age=22, sex=女, email=ddd@obj.com]
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        而如果只有第一个条件没有传递进来,会智能地去掉第一个无用的and,执行结果如下所示。

Preparing: select * from t_person WHERE person_sex=? and person_age>? 
Parameters: 男(String), 20(Integer)
Total: 3
Person [id=3, name=ccc, age=21, sex=男, email=ccc@obj.com]
Person [id=5, name=abc, age=23, sex=男, email=abc@obj.com]
Person [id=6, name=abd, age=24, sex=男, email=abd@obj.com]

        这样看来where标签功能确实强大,其适用的地方就是不确定的条件语句,适时地插入where语句,并且可以智能地去掉多余的and或or语句。另外,where标签不仅仅适用于查询操作,其他的操作同样适用。

        不过MyBatis为了防止where语句不能正常执行,提供了trim标签。从字面意思上看trim意为修剪,在实际的应用中也是这个意思,上面的代码可以修改为。

<select id="dynamicLoad"  parameterType="Person" resultMap="personMap">select * from t_person <trim prefix="where" prefixOverrides="and |or"><if test="name != null">person_name like "%"#{name}"%"</if><if test="sex != null">and person_sex=#{sex}</if><if test="age > 0">and person_age>#{age}</if></trim>
</select>

        其中属性prefix为前缀,执行的过程中会在条件之前加上where语句,prefixOverrides可以去掉指定的语句,其中的and和or就是指定的语句,不要忘了中间有一个空格。除此之外trim标签中还有另外两个属性,分别是suffix(后缀)和suffixOverrides(指定去掉的语句),使用方法是相同的。

        在MyBatis动态SQL语句中,还有一个set标签用来执行修改操作的动态语句。我们都知道在执行修改操作的时候有一个“set”语句,并且在所有的修改字段语句之间都有一个逗号,这样一来如果使用普通的动态修改语句,会导致在语句中多一些逗号,造成语句执行错误。具体的语句如下。

<update id="dynamicUpdate" parameterType="Person">update t_person <set><if test="name != null">person_name=#{name},</if><if test="sex != null">person_sex=#{sex},</if><if test="age > 0">person_age=#{age},</if><if test="email != null">person_email=#{email}</if></set>where person_id=#{id}
</update>

        在执行的过程中,会加上set语句,并且如果其中的第一个条件没有传入数据,或者最后一个条件没有传入数据,都会多一个逗号,在执行的过程中,会自动去掉多余的逗号。

        同样,也可以使用trim语句来替换上述代码,具体的操作代码如下。

<update id="dynamicUpdate" parameterType="Person">update t_person <trim prefix="set" prefixOverrides=","><if test="name != null">person_name=#{name},</if><if test="sex != null">person_sex=#{sex},</if><if test="age > 0">person_age=#{age},</if><if test="email != null">person_email=#{email}</if></trim>where person_id=#{id}
</update>

foreach——循环遍历语句

        在动态SQL语句中还有一个常用的foreach语句,用来执行循环遍历操作,特别是在in语句中经常用到,具体的代码如下。

<select id="dynamicList" resultMap="personMap">select * from t_person where person_id in<foreach collection="list" item="id" index="i" open="(" close=")" separator=",">#{id}</foreach>
</select>

        其中collection属性用来指定具体遍历的类型,其中的属性值有三个,分别是list、map和array,分别对应List集合、Map集合和数组。item属性是用来指定具体遍历的对象,要和下面的参数#{id}对应。index属性是用来指定每次遍历元素的下标,open和close分别表示前缀和后缀,separator表示每个条件之间的分隔符。

        具体的测试代码如下所示。

java">@Test
public void testDynamicList() {SqlSession session = null;try {session = factory.openSession();List<Integer> ids = new ArrayList<Integer>();ids.add(1);ids.add(2);ids.add(3);List<Person> persons = session.selectList("com.obj.model.Person.dynamicList", ids);for(Person person:persons) {System.out.println(person);}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}
}

        具体的执行结果如下所示。

Preparing: select * from t_person where person_id in ( ? , ? , ? ) 
Parameters: 1(Integer), 2(Integer), 3(Integer)
Total: 3
Person [id=1, name=aaa, age=20, sex=男, email=aaa@obj.com]
Person [id=2, name=bbb, age=20, sex=女, email=bbb@obj.com]
Person [id=3, name=ccc, age=21, sex=男, email=ccc@obj.com]

        foreach通常用于执行批量删除和批量添加等操作。


http://www.ppmy.cn/embedded/13184.html

相关文章

中级信息系统管理工程师-易错题锦集

易错题 题目一&#xff1a; 电子政务根据其服务的对象不同&#xff0c;基本上可以分为四种模式。某政府部门内部的“办公自动化系统”属于模式。 A. G2B B. G2C C. G2E D. G2G 解析&#xff1a; 电子政务根据其服务对象的不同&#xff0c;基本上可以分为四种模式&#xff0c;即…

基于模糊控制的纯跟踪横向控制在倒车中的应用及实现

文章目录 1. 引言2. Pure Pursuit在倒车场景的推导3. 模糊控制器的设计3.1 基础知识3.2 预瞄距离系数k的模糊控制器设计 4. 算法和仿真实现 1. 引言 Pure Pursuit是一种几何跟踪控制算法&#xff0c;也被称为纯跟踪控制算法。他的思想就是基于当前车辆的后轮中心的位置&#x…

C# Solidworks二次开发:比较两个solidworks文档属性相关API详解

大家好&#xff0c;今天要讲的文章是关于如何比较两个solidworks文档。 下面是API的介绍&#xff1a; &#xff08;1&#xff09;第一个为Close&#xff0c;这个API的含义为在比较solidworks文档以后执行必要的清理。下面是官方的具体解释&#xff1a; 其没有输入参数&#x…

Conda的使用:创建一个虚拟环境

问&#xff1a;使用conda环境&#xff0c;像python3 -m venv ocrenv一样创建一个虚拟环境&#xff1f; conda create -n ocrenv python3.8这里-n ocrenv指定了虚拟环境的名字&#xff0c;python3.8指定了要安装的Python版本。可以根据需要选择安装不同的Python版本。激活虚拟环…

怎么在电脑桌面上添加待办事项?

对于上班族来说&#xff0c;每天面对繁杂的工作任务&#xff0c;很容易遗漏或混淆重要事项。因此&#xff0c;在电脑桌面上添加待办事项清单显得尤为重要。这样做的好处是&#xff0c;能够随时查看和跟进任务&#xff0c;确保每项工作都能按时完成。例如&#xff0c;将一天中的…

为什么要分库分表?(设计高并发系统的时候,数据库层面该如何设计?)

目录 1.分表 2.分库 说白了&#xff0c;分库分表是两回事儿&#xff0c;大家可别搞混了&#xff0c;可能是光分库不分表&#xff0c;也可能是光分表不分库&#xff0c;都有可能。 我先给大家抛出来一个场景。 假如我们现在是一个小创业公司(或者是一个 BAT …

JVM(1)

目录 1.类加载的生命周期? 2.类加载器的层次? 3.Class.forName()和ClassLoader.loadClass()的区别? 4.JVM类加载器机制有哪些? 5.双亲委派机制过程? 6.说说JVM内存整体结构,线程私有还是共享的? 7.什么是程序计数器(线程私有)? 8.什么是虚拟机栈(线程私有)?…

电子温度计不准需要怎么处理?

电子温度计不准需要怎么处理&#xff1f; 首选将温度计完全浸入温度为0℃左右的水中&#xff0c;使温度计指示值与0℃相等&#xff0c;拿出测量待测物的温度。其次将温度计完全浸入温度为100℃左右的水中&#xff0c;使温度计指示值与100℃相等&#xff0c;拿出测量待测物的温…