- 浏览: 2117344 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
wahahachuang5:
web实时推送技术使用越来越广泛,但是自己开发又太麻烦了,我觉 ...
细说websocket - php篇 -
wahahachuang8:
挺好的,学习了
细说websocket - php篇 -
jacking124:
学习了!支持你,继续
初窥Linux 之 我最常用的20条命令 -
aliahhqcheng:
应该是可以实现的,没有看过源码。你可以参考下:http://w ...
Jackson 框架,轻易转换JSON
MyBatis 动态SQL语句
MyBatis学习 之 一、MyBatis简介与配置MyBatis+Spring+MySql
MyBatis学习 之 二、SQL语句映射文件(1)resultMap
MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
有些时候,sql语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息。使用Oracle的序列、mysql的函数生成Id。这时我们可以使用动态sql。
下文均采用mysql语法和函数(例如字符串链接函数CONCAT)。
3.1 selectKey标签
在insert语句中,在Oracle经常使用序列、在MySQL中使用函数来自动生成插入表的主键,而且需要方法能返回这个生成主键。使用myBatis的selectKey标签可以实现这个效果。
下面例子,使用mysql数据库自定义函数nextval('student'),用来生成一个key,并把他设置到传入的实体类中的studentId属性上。所以在执行完此方法后,边可以通过这个实体类获取生成的key。
- <!--插入学生自动主键-->
- <insertid="createStudentAutoKey"parameterType="liming.student.manager.data.model.StudentEntity"keyProperty="studentId">
- <selectKeykeyProperty="studentId"resultType="String"order="BEFORE">
- selectnextval('student')
- </selectKey>
- INSERTINTOSTUDENT_TBL(STUDENT_ID,
- STUDENT_NAME,
- STUDENT_SEX,
- STUDENT_BIRTHDAY,
- STUDENT_PHOTO,
- CLASS_ID,
- PLACE_ID)
- VALUES(#{studentId},
- #{studentName},
- #{studentSex},
- #{studentBirthday},
- #{studentPhoto,javaType=byte[],jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler},
- #{classId},
- #{placeId})
- </insert>
调用接口方法,和获取自动生成key
- StudentEntityentity=newStudentEntity();
- entity.setStudentName("黎明你好");
- entity.setStudentSex(1);
- entity.setStudentBirthday(DateUtil.parse("1985-05-28"));
- entity.setClassId("20000001");
- entity.setPlaceId("70000001");
- this.dynamicSqlMapper.createStudentAutoKey(entity);
- System.out.println("新增学生ID:"+entity.getStudentId());
selectKey语句属性配置细节:
属性 | 描述 | 取值 |
keyProperty | selectKey语句生成结果需要设置的属性。 | |
resultType | 生成结果类型,MyBatis允许使用基本的数据类型,包括String、int类型。 | |
order |
1:BEFORE,会先选择主键,然后设置keyProperty,再执行insert语句; 2:AFTER,就先运行insert语句再运行selectKey语句。 |
BEFORE AFTER |
statementType | MyBatis支持STATEMENT,PREPARED和CALLABLE的语句形式,对应Statement,PreparedStatement和CallableStatement响应 |
STATEMENT PREPARED CALLABLE |
3.2 if标签
if标签可用在许多类型的sql语句中,我们以查询为例。首先看一个很普通的查询:
- <!--查询学生list,like姓名-->
- <selectid="getStudentListLikeName"parameterType="StudentEntity"resultMap="studentResultMap">
- SELECT*fromSTUDENT_TBLST
- WHEREST.STUDENT_NAMELIKECONCAT(CONCAT('%',#{studentName}),'%')
- </select>
但是此时如果studentName或studentSex为null,此语句很可能报错或查询结果为空。此时我们使用if动态sql语句先进行判断,如果值为null或等于空字符串,我们就不进行此条件的判断,增加灵活性。
参数为实体类StudentEntity。将实体类中所有的属性均进行判断,如果不为空则执行判断条件。
- <!--2if(判断参数)-将实体类不为空的属性作为where条件-->
- <selectid="getStudentList_if"resultMap="resultMap_studentEntity"parameterType="liming.student.manager.data.model.StudentEntity">
- SELECTST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROMSTUDENT_TBLST
- WHERE
- <iftest="studentName!=null">
- ST.STUDENT_NAMELIKECONCAT(CONCAT('%',#{studentName,jdbcType=VARCHAR}),'%')
- </if>
- <iftest="studentSex!=nullandstudentSex!=''">
- ANDST.STUDENT_SEX=#{studentSex,jdbcType=INTEGER}
- </if>
- <iftest="studentBirthday!=null">
- ANDST.STUDENT_BIRTHDAY=#{studentBirthday,jdbcType=DATE}
- </if>
- <iftest="classId!=nullandclassId!=''">
- ANDST.CLASS_ID=#{classId,jdbcType=VARCHAR}
- </if>
- <iftest="classEntity!=nullandclassEntity.classId!=nullandclassEntity.classId!=''">
- ANDST.CLASS_ID=#{classEntity.classId,jdbcType=VARCHAR}
- </if>
- <iftest="placeId!=nullandplaceId!=''">
- ANDST.PLACE_ID=#{placeId,jdbcType=VARCHAR}
- </if>
- <iftest="placeEntity!=nullandplaceEntity.placeId!=nullandplaceEntity.placeId!=''">
- ANDST.PLACE_ID=#{placeEntity.placeId,jdbcType=VARCHAR}
- </if>
- <iftest="studentId!=nullandstudentId!=''">
- ANDST.STUDENT_ID=#{studentId,jdbcType=VARCHAR}
- </if>
- </select>
使用时比较灵活,new一个这样的实体类,我们需要限制那个条件,只需要附上相应的值就会where这个条件,相反不去赋值就可以不在where中判断。
- publicvoidselect_test_2_1(){
- StudentEntityentity=newStudentEntity();
- entity.setStudentName("");
- entity.setStudentSex(1);
- entity.setStudentBirthday(DateUtil.parse("1985-05-28"));
- entity.setClassId("20000001");
- //entity.setPlaceId("70000001");
- List<StudentEntity>list=this.dynamicSqlMapper.getStudentList_if(entity);
- for(StudentEntitye:list){
- System.out.println(e.toString());
- }
- }
3.3 if + where的条件判断
当where中的条件使用的if标签较多时,这样的组合可能会导致错误。我们以在3.1中的查询语句为例子,当java代码按如下方法调用时:
- @Test
- publicvoidselect_test_2_1(){
- StudentEntityentity=newStudentEntity();
- entity.setStudentName(null);
- entity.setStudentSex(1);
- List<StudentEntity>list=this.dynamicSqlMapper.getStudentList_if(entity);
- for(StudentEntitye:list){
- System.out.println(e.toString());
- }
- }
如果上面例子,参数studentName为null,将不会进行STUDENT_NAME列的判断,则会直接导“WHERE AND”关键字多余的错误SQL。
这时我们可以使用where动态语句来解决。这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND或OR开头的,则它会剔除掉。
上面例子修改为:
- <!--3select-where/if(判断参数)-将实体类不为空的属性作为where条件-->
- <selectid="getStudentList_whereIf"resultMap="resultMap_studentEntity"parameterType="liming.student.manager.data.model.StudentEntity">
- SELECTST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROMSTUDENT_TBLST
- <where>
- <iftest="studentName!=null">
- ST.STUDENT_NAMELIKECONCAT(CONCAT('%',#{studentName,jdbcType=VARCHAR}),'%')
- </if>
- <iftest="studentSex!=nullandstudentSex!=''">
- ANDST.STUDENT_SEX=#{studentSex,jdbcType=INTEGER}
- </if>
- <iftest="studentBirthday!=null">
- ANDST.STUDENT_BIRTHDAY=#{studentBirthday,jdbcType=DATE}
- </if>
- <iftest="classId!=nullandclassId!=''">
- ANDST.CLASS_ID=#{classId,jdbcType=VARCHAR}
- </if>
- <iftest="classEntity!=nullandclassEntity.classId!=nullandclassEntity.classId!=''">
- ANDST.CLASS_ID=#{classEntity.classId,jdbcType=VARCHAR}
- </if>
- <iftest="placeId!=nullandplaceId!=''">
- ANDST.PLACE_ID=#{placeId,jdbcType=VARCHAR}
- </if>
- <iftest="placeEntity!=nullandplaceEntity.placeId!=nullandplaceEntity.placeId!=''">
- ANDST.PLACE_ID=#{placeEntity.placeId,jdbcType=VARCHAR}
- </if>
- <iftest="studentId!=nullandstudentId!=''">
- ANDST.STUDENT_ID=#{studentId,jdbcType=VARCHAR}
- </if>
- </where>
- </select>
3.4 if + set的更新语句
当update语句中没有使用if标签时,如果有一个参数为null,都会导致错误。
当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置SET关键字,和剔除追加到条件末尾的任何不相关的逗号。
使用if+set标签修改后,如果某项为null则不进行更新,而是保持数据库原值。如下示例:
- <!--4if/set(判断参数)-将实体类不为空的属性更新-->
- <updateid="updateStudent_if_set"parameterType="liming.student.manager.data.model.StudentEntity">
- UPDATESTUDENT_TBL
- <set>
- <iftest="studentName!=nullandstudentName!=''">
- STUDENT_TBL.STUDENT_NAME=#{studentName},
- </if>
- <iftest="studentSex!=nullandstudentSex!=''">
- STUDENT_TBL.STUDENT_SEX=#{studentSex},
- </if>
- <iftest="studentBirthday!=null">
- STUDENT_TBL.STUDENT_BIRTHDAY=#{studentBirthday},
- </if>
- <iftest="studentPhoto!=null">
- STUDENT_TBL.STUDENT_PHOTO=#{studentPhoto,javaType=byte[],jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler},
- </if>
- <iftest="classId!=''">
- STUDENT_TBL.CLASS_ID=#{classId}
- </if>
- <iftest="placeId!=''">
- STUDENT_TBL.PLACE_ID=#{placeId}
- </if>
- </set>
- WHERESTUDENT_TBL.STUDENT_ID=#{studentId};
- </update>
3.5 if + trim代替where/set标签
trim是更灵活的去处多余关键字的标签,他可以实践where和set的效果。
3.5.1trim代替where
- <!--5.1if/trim代替where(判断参数)-将实体类不为空的属性作为where条件-->
- <selectid="getStudentList_if_trim"resultMap="resultMap_studentEntity">
- SELECTST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROMSTUDENT_TBLST
- <trimprefix="WHERE"prefixOverrides="AND|OR">
- <iftest="studentName!=null">
- ST.STUDENT_NAMELIKECONCAT(CONCAT('%',#{studentName,jdbcType=VARCHAR}),'%')
- </if>
- <iftest="studentSex!=nullandstudentSex!=''">
- ANDST.STUDENT_SEX=#{studentSex,jdbcType=INTEGER}
- </if>
- <iftest="studentBirthday!=null">
- ANDST.STUDENT_BIRTHDAY=#{studentBirthday,jdbcType=DATE}
- </if>
- <iftest="classId!=nullandclassId!=''">
- ANDST.CLASS_ID=#{classId,jdbcType=VARCHAR}
- </if>
- <iftest="classEntity!=nullandclassEntity.classId!=nullandclassEntity.classId!=''">
- ANDST.CLASS_ID=#{classEntity.classId,jdbcType=VARCHAR}
- </if>
- <iftest="placeId!=nullandplaceId!=''">
- ANDST.PLACE_ID=#{placeId,jdbcType=VARCHAR}
- </if>
- <iftest="placeEntity!=nullandplaceEntity.placeId!=nullandplaceEntity.placeId!=''">
- ANDST.PLACE_ID=#{placeEntity.placeId,jdbcType=VARCHAR}
- </if>
- <iftest="studentId!=nullandstudentId!=''">
- ANDST.STUDENT_ID=#{studentId,jdbcType=VARCHAR}
- </if>
- </trim>
- </select>
3.5.2 trim代替set
- <!--5.2if/trim代替set(判断参数)-将实体类不为空的属性更新-->
- <updateid="updateStudent_if_trim"parameterType="liming.student.manager.data.model.StudentEntity">
- UPDATESTUDENT_TBL
- <trimprefix="SET"suffixOverrides=",">
- <iftest="studentName!=nullandstudentName!=''">
- STUDENT_TBL.STUDENT_NAME=#{studentName},
- </if>
- <iftest="studentSex!=nullandstudentSex!=''">
- STUDENT_TBL.STUDENT_SEX=#{studentSex},
- </if>
- <iftest="studentBirthday!=null">
- STUDENT_TBL.STUDENT_BIRTHDAY=#{studentBirthday},
- </if>
- <iftest="studentPhoto!=null">
- STUDENT_TBL.STUDENT_PHOTO=#{studentPhoto,javaType=byte[],jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler},
- </if>
- <iftest="classId!=''">
- STUDENT_TBL.CLASS_ID=#{classId},
- </if>
- <iftest="placeId!=''">
- STUDENT_TBL.PLACE_ID=#{placeId}
- </if>
- </trim>
- WHERESTUDENT_TBL.STUDENT_ID=#{studentId}
- </update>
3.6 choose (when, otherwise)
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。而使用if标签时,只要test中的表达式为true,就会执行if标签中的条件。MyBatis提供了choose 元素。if标签是与(and)的关系,而choose比傲天是或(or)的关系。
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行otherwise中的sql。类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。
例如下面例子,同样把所有可以限制的条件都写上,方面使用。choose会从上到下选择一个when标签的test为true的sql执行。安全考虑,我们使用where将choose包起来,放置关键字多于错误。
- <!--6choose(判断参数)-按顺序将实体类第一个不为空的属性作为where条件-->
- <selectid="getStudentList_choose"resultMap="resultMap_studentEntity"parameterType="liming.student.manager.data.model.StudentEntity">
- SELECTST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROMSTUDENT_TBLST
- <where>
- <choose>
- <whentest="studentName!=null">
- ST.STUDENT_NAMELIKECONCAT(CONCAT('%',#{studentName,jdbcType=VARCHAR}),'%')
- </when>
- <whentest="studentSex!=nullandstudentSex!=''">
- ANDST.STUDENT_SEX=#{studentSex,jdbcType=INTEGER}
- </when>
- <whentest="studentBirthday!=null">
- ANDST.STUDENT_BIRTHDAY=#{studentBirthday,jdbcType=DATE}
- </when>
- <whentest="classId!=nullandclassId!=''">
- ANDST.CLASS_ID=#{classId,jdbcType=VARCHAR}
- </when>
- <whentest="classEntity!=nullandclassEntity.classId!=nullandclassEntity.classId!=''">
- ANDST.CLASS_ID=#{classEntity.classId,jdbcType=VARCHAR}
- </when>
- <whentest="placeId!=nullandplaceId!=''">
- ANDST.PLACE_ID=#{placeId,jdbcType=VARCHAR}
- </when>
- <whentest="placeEntity!=nullandplaceEntity.placeId!=nullandplaceEntity.placeId!=''">
- ANDST.PLACE_ID=#{placeEntity.placeId,jdbcType=VARCHAR}
- </when>
- <whentest="studentId!=nullandstudentId!=''">
- ANDST.STUDENT_ID=#{studentId,jdbcType=VARCHAR}
- </when>
- <otherwise>
- </otherwise>
- </choose>
- </where>
- </select>
3.7 foreach
对于动态SQL非常必须的,主是要迭代一个集合,通常是用于IN条件。List实例将使用“list”做为键,数组实例以“array”做为键。
foreach元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
注意:你可以传递一个List实例或者数组作为参数对象传给MyBatis。当你这么做的时候,MyBatis会自动将它包装在一个Map中,用名称在作为键。List实例将会以“list”作为键,而数组实例将会以“array”作为键。
这个部分是对关于XML配置文件和XML映射文件的而讨论的。下一部分将详细讨论Java API,所以你可以得到你已经创建的最有效的映射。
3.7.1参数为array示例的写法
接口的方法声明:
动态SQL语句:
- <!—7.1foreach(循环array参数)-作为where中in的条件-->
- <selectid="getStudentListByClassIds_foreach_array"resultMap="resultMap_studentEntity">
- SELECTST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROMSTUDENT_TBLST
- WHEREST.CLASS_IDIN
- <foreachcollection="array"item="classIds"open="("separator=","close=")">
- #{classIds}
- </foreach>
- </select>
测试代码,查询学生中,在20000001、20000002这两个班级的学生:
- @Test
- publicvoidtest7_foreach(){
- String[]classIds={"20000001","20000002"};
- List<StudentEntity>list=this.dynamicSqlMapper.getStudentListByClassIds_foreach_array(classIds);
- for(StudentEntitye:list){
- System.out.println(e.toString());
- }
- <p>}<spanstyle="font-size:14px;font-weight:bold;white-space:normal;"></span></p>
3.7.2参数为list示例的写法
接口的方法声明:
动态SQL语句:
- <!--7.2foreach(循环List<String>参数)-作为where中in的条件-->
- <selectid="getStudentListByClassIds_foreach_list"resultMap="resultMap_studentEntity">
- SELECTST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROMSTUDENT_TBLST
- WHEREST.CLASS_IDIN
- <foreachcollection="list"item="classIdList"open="("separator=","close=")">
- #{classIdList}
- </foreach>
- </select>
测试代码,查询学生中,在20000001、20000002这两个班级的学生:
- @Test
- publicvoidtest7_2_foreach(){
- ArrayList<String>classIdList=newArrayList<String>();
- classIdList.add("20000001");
- classIdList.add("20000002");
- List<StudentEntity>list=this.dynamicSqlMapper.getStudentListByClassIds_foreach_list(classIdList);
- for(StudentEntitye:list){
- System.out.println(e.toString());
- }
- }
MyBatis学习 之 一、MyBatis简介与配置MyBatis+Spring+MySql
MyBatis学习 之 二、SQL语句映射文件(1)resultMap
MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
相关推荐
if 、where、set、trim、choose 、foreach等在mybatis中的具体用法,有具体实例可供参考,玩转mybatis
JDBC读取数据库元数据,生成JAVA实体类,SQL语句,Mybatis动态sql语句,详细内容见博客地址https://blog.csdn.net/zi971553/article/details/82862039
mybatis动态sql
在实际开发过程中,我们往往需要编写复杂的SQL语句,拼接稍有不注意就会导致错误,Mybatis给开发者提供了动态SQL,大大降低了拼接SQL导致的错误。 动态标签 if标签 if标签通常用那个胡where语句,update语句,insert...
Mybatis执行SQL语句的方式
mybatis动态SQL语句--基于xml配置。
其中,动态SQL是MyBatis的一个重要特性,它允许用户根据不同的条件拼接SQL语句,从而实现更加灵活和可扩展的数据库操作。 在MyBatis中,动态SQL使用的主要方式是通过使用XML或注解来编写SQL语句。下面我将简单介绍...
附件是MyBatis 动态 SQL 示例,MyBatis 是一个持久层框架,它允许用户在 XML 文件中编写动态 SQL 语句。MyBatis 的动态 SQL 功能非常强大,它允许开发者根据运行时的条件动态地生成 SQL 语句。这使得 MyBatis 能够...
附件是MyBatis 动态SQL示例,MyBatis 是一个持久层框架,它允许用户在 XML 文件中编写动态 SQL 语句。MyBatis 的动态 SQL 功能非常强大,它允许开发者根据运行时的条件动态地生成 SQL 语句。这使得 MyBatis 能够灵活...
适用于springboot(整合过mybatis的)和常规SSM项目,可以获取完整的mybatis执行的sql语句,用于直观的看到执行sql是否异常
在数据库操作中,经常需要根据不同的业务逻辑和条件来构建动态的SQL语句。传统的硬编码SQL语句在面对复杂的业务逻辑时显得笨拙且难以维护。MyBatis框架通过其独特的动态SQL机制,极大地简化了这一过程。本文将详细...
mybatis+spring 框架中配置日志中显示sql语句
把 mybatis 输出的sql日志还原成完整的sql语句。 将日志输出的sql语句中的问号 ? 替换成真正的参数值。 通过 "Tools -> MyBatis Log Plugin" 菜单或快捷键 "Ctrl+Shift+Alt+O" 启用。 点击窗口左边的 "Filter" ...
mybatis动态sqlMyBatis动态SQL是一种强大的特性,它允许我们在SQL语句中根据条件动态地添加或删除某些部分,从而实现更加灵活和高效的数据库操作。在JDBC或其他类似框架中,开发人员通常需要手动拼接SQL语句,这既...
动态SQL是一种根据不同条件动态生成SQL语句的技术。在Mabits中,动态SQL通常是通过使用一组特殊的标签和代码块来实现的,这些标签和代码块可以根据条件包含或排除不同的部分,从而生成不同的SQL语句。动态SQL可以让...
MyBatis动态SQL是一项强大的特性,它允许我们在编写SQL语句时根据条件动态地添加或删除某些部分,从而实现更加灵活和高效的数据库操作。这一特性在应对复杂多变的业务需求时尤为重要,能够极大地提高SQL语句的复用性...