Java EE轻量级框架应用实战-SSM框架(Spring MVC+Spring+MyBatis)(第2版)课件 第3、4章 动态SQL语句、MyBatis的关联映射_第1页
Java EE轻量级框架应用实战-SSM框架(Spring MVC+Spring+MyBatis)(第2版)课件 第3、4章 动态SQL语句、MyBatis的关联映射_第2页
Java EE轻量级框架应用实战-SSM框架(Spring MVC+Spring+MyBatis)(第2版)课件 第3、4章 动态SQL语句、MyBatis的关联映射_第3页
Java EE轻量级框架应用实战-SSM框架(Spring MVC+Spring+MyBatis)(第2版)课件 第3、4章 动态SQL语句、MyBatis的关联映射_第4页
Java EE轻量级框架应用实战-SSM框架(Spring MVC+Spring+MyBatis)(第2版)课件 第3、4章 动态SQL语句、MyBatis的关联映射_第5页
已阅读5页,还剩102页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

动态SQL语句主要元素使用动态SQL语句实现多条件查询使用动态SQL语句实现更新使用<foreach>元素实现复杂查询使用<bind>元素实现SQL语句拼接第3章

动态SQL语句2024/1/29回顾与作业点评2MyBatis基本要素核心对象SqlSessionFactoryBuilderSqlSessionFactorySqlSession通过SqlSession实例直接运行映射的SQL语句基于mapper接口的方式执行SQL语句系统核心配置文件propertiestypeAliasesenvironmentsmappersSQL映射文件核心对象最佳生命周期最佳作用域SqlSessionFactoryBuilder方法体内方法体内(局部变量)SqlSessionFactory从应用服务启动开始一直到应用服务停止—application整个应用内SqlSession一次请求的有效期一次请求的有效期内回顾作业点评点评作业的提交情况和共性问题学习目标/Target3

了解动态SQL语句中的主要元素及其说明掌握动态SQL语句中主要元素的使用方法

熟练掌握动态SQL语句的运用章节概述/Summary4在实际项目的开发中,开发人员在使用JDBC或其他持久层框架进行开发时,经常需要根据不同的条件拼接SQL语句,拼接SQL语句时还要确保不能遗漏必要的空格、标点符号等,这种编程方式给开发人员带来了非常大的不便,而MyBatis提供的SQL语句动态组装功能,恰能很好的解决这一问题。本章将对MyBatis框架的动态SQL进行详细讲解。

目录/CONTENTS动态SQL语句主要元素使用<foreach>元素实现复杂查询使用动态SQL语句实现更新使用动态SQL语句实现多条件查询5使用<bind>元素实现SQL语句拼接14325动态SQL语句

主要元素01第3章动态SQL语句动态SQL有什么作用?动态SQL中的元素7

开发人员在使用JDBC或其他类似的框架进行数据库开发时,通常都要根据需求去手动拼装SQL,这是一个非常麻烦且痛苦的工作,而MyBatis提供的对SQL语句动态组装的功能,恰能很好的解决这一麻烦工作。STEP01

动态SQL是MyBatis的强大特性之一,MyBatis采用了功能强大的基于OGNL(ObjectGraphNavigationLanguage)的表达式来完成动态SQL。在MyBatis的映射文件中,开发人员可通过动态SQL元素灵活组装SQL语句,这在很大程度上避免了单一SQL语句的反复堆砌,提高了SQL语句的复用性。STEP03使用动态SQL的好处动态SQL中的元素8动态SQL中的元素9

动态SQL是MyBatis的强大特性之一,MyBatis3采用了功能强大的基于OGNL的表达式来完成动态SQL。动态SQL主要元素如下表所示:SQL元素说明<if>判断语句,用于单条件分支判断<choose>(<when>、<otherwise>)相当于Java中的switch...case...default语句,用于多条件分支判断<where>简化SQL语句中where的条件判断。<trim>可以灵活地去除多余的关键字。<set>解决动态更新语句。<foreach>循环语句,常用于in语句等列举条件中<bind>从OGNL表达式中创建一个变量,并将其绑定到上下文,常用于模糊查询的sql中动态SQL10基于OGNL表达式完成多条件查询等逻辑实现用于实现动态SQL的元素主要有iftrimwheresetchoose(when、otherwise)foreach使用动态SQL语句实现多条件查询02第3章动态SQL语句STEP01

在MyBatis中,<if>元素是最常用的判断元素,它类似于Java中的if语句,主要用于实现某些简单的条件判断。在实际应用中,我们可能会通过某个条件查询某个数据。例如,要查找某个客户的信息,可以通过姓名或者年龄来查找客户,也可以不填写年龄直接通过姓名来查找客户,还可以都不填写而查询出所有客户,此时姓名和年龄就是非必须条件。类似于这种情况,在MyBatis中就可以通过<if>元素来实现。STEP03<if>元素的应用<if>元素12<if>元素13

在MyBatis中,<if>元素是最常用的判断语句,它类似于Java中的if语句,主要用于实现某些简单的条件选择。其基本使用示例如下:select*fromtb_userwhere1=1<iftest="username!=nullandusername!=''"> andusernamelikeconcat('%',#{username},'%')</if><iftest="jobs!=nullandjobs!=''"> andjobs=#{jobs}</if>使用<if>元素对username和jobs进行非空判断,并动态组装SQL<if>元素14需求说明改造查询用户信息列表的演示示例,增加查询条件用户角色(根据角色id查询)用户名称(模糊查询)演示示例:改造用户表的查询操作-多条件查询<if>元素15当传入用户角色参数为空的时候,检索结果为空?正确结果所有用户角色下的用户数据原因如何处理if(判断参数):实现简单的条件判断问题分析select*fromtb_useru,tb_roler whereu.userRole=r.idandu.userNamelikeCONCAT(‘%’,‘’,‘%’) andu.userRole=null;演示示例

:改造用户表的查询操作-if<where>元素16当只传入参数:用户角色,而不传入参数:用户名称的时候,控制台报SQL异常错误?正确结果指定用户角色下的所有用户数据原因如何处理where问题分析select*fromtb_userwhereanduserRole=?<where>元素17where简化SQL语句中where条件判断智能处理and和or演示示例:改造用户表的查询操作-if+where改造订单表查询(if)18需求说明改造订单表的查询功能,使用动态SQL完善此功能查询条件商品名称(模糊查询)供应商id是否付款查询结果列列表订单id、订单编码、商品名称、供应商id、供应商名称、订单金额、是否付款、创建时间修改SQL语句–使用if完成时间:15分钟练习指导改造供应商表查询(if+where)19需求说明改造供应商表的查询功能,使用动态SQL完善此功能查询条件供应商编码(模糊查询)供应商名称(模糊查询)查询结果列列表供应商id、供应商编码、供应商名称、联系人、联系电话、传真、创建时间修改SQL语句–使用if+where组合完成时间:15分钟练习指导共性问题集中讲解20常见问题及解决办法代码规范问题调试技巧共性问题集中讲解

<trim>元素用于删除多余的关键字,它可以直接实现<where>元素的功能。<trim>元素包含4个属性。

<trim>元素

21属性说明prefix

指定给SQL语句增加的前缀prefixOverrides

指定SQL语句中要去掉的前缀字符串suffix

指定给SQL语句增加的后缀suffixOverrides

指定SQL语句中要去掉的后缀字符串<trim>元素22trim属性prefixsuffixprefixOverridessuffixOverrides更灵活地去除多余关键字替代where和set<selectid="getUserList5"resultType="User"> select*fromtb_user

<trimprefix="where"prefixOverrides="and|or"> <iftest="userName!=nullanduserName!=''"> anduserNamelikeCONCAT('%',#{userName},'%') </if> <iftest="userRole!=null"> anduserRole=#{userRole} </if> </trim></select>

上述配置代码中,<trim>元素的作用是去除一些多余的前缀字符串,它的prefix属性代表的是语句的前缀(where),而prefixOverrides属性代表的是需要去除的前缀字符串(SQL中的“AND”或“OR”)。

<where>、<trim>元素23

在前两个小节的案例中,映射文件中编写的SQL后面都加入了“where1=1”的条件,那么到底为什么要这么写呢?如果将where后“1=1”的条件去掉,那么MyBatis所拼接出来的SQL将会如下所示:select*fromtb_userwhereandusernamelikeconcat('%',?,'%')

可以看出上面SQL语句明显存在SQL语法错误,而加入了条件“1=1”后,既保证了where后面的条件成立,又避免了where后面第一个词是and或者or之类的关键词。不过“where1=1”这种写法对于初学者来将不容易理解,并且也不够雅观。<where>、<trim>元素24select*fromt_customerwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>

针对上述情况中“where1=1”,在MyBatis的SQL中就可以使用<where>或<trim>元素进行动态处理。<where>会自动判断SQL语句,只有<where>内的条件成立时,才会在拼接SQL中加入where关键字,否则将不会添加;还会去除多余的“AND”或“OR”。<where>元素处理<trim>元素处理<trim>的作用是去除特殊的字符串,它的prefix属性代表语句的前缀,prefixOverrides属性代表需要去除的哪些特殊字符串,功能和<where>基本是等效的。动态SQL处理“where1=1”select*fromtb_user<where><iftest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</if><iftest="jobs!=nullandjobs!=''">andjobs=#{jobs}</if></where>select*fromtb_user<trimprefix="where"prefixOverrides="and"><iftest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</if><iftest="jobs!=nullandjobs!=''">andjobs=#{jobs}</if></trim>STEP01

在使用<if>元素时,只要test属性中的表达式为true,就会执行元素中的条件语句,但是在实际应用中,有时只需要从多个选项中选择一个去执行。

例如下面的场景:“当客户名称不为空,则只根据客户名称进行客户筛选;当客户名称为空,而客户职业不为空,则只根据客户职业进行客户筛选。当客户名称和客户职业都为空,则要求查询出所有电话不为空的客户信息。”

针对上面情况,使用<if>元素进行处理是不合适的。MyBatis提供了<choose>、<when>、<otherwise>元素进行处理,这三个元素往往组合在一起使用,作用相当于Java语言中的if…elseif…else。STEP03<choose><when>otherwise>使用场景<choose>、<when>、<otherwise>元素25<choose>、<when>、<otherwise>元素26“当客户名称不为空,则只根据客户名称进行客户筛选;

当客户名称为空,而客户职业不为空,则只根据客户职业进行客户筛选。

当客户名称和客户职业都为空,则要求查询出所有电话不为空的客户信息。”假设如下场景:

这种情况下,使用<if>元素进行处理是非常不合适的。如果使用的是Java语言,这种情况显然更适合使用switch…case…default语句来处理,而在SQL中就可以使用<choose>、<when>、<otherwise>元素组合进行处理。其基本使用示例如代码所示:select*fromtb_userwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>使用<choose>及其子元素依次对条件进行非空判断,并动态组装SQLchoose(when、otherwise)27choose(when、otherwise)相当于Java中switch语句当when有条件满足的时候,就跳出choose演示示例:改造用户表的查询操作-choose<choose> <whentest="条件1">…</when> <whentest="条件2">…</when> <whentest="条件3">…</when> … <otherwise>…</otherwise></choose> 改造供应商列表查询-choose28需求说明实现按条件查询供应商表,查询条件如下供应商编码(模糊查询)供应商名称(模糊查询)供应商联系人(模糊查询)创建时间在本年内(时间范围)查询结果列显示:供应商id、供应商编码、供应商名称、供应商联系人、创建时间choose(when、otherwise)完成时间:15分钟练习指导共性问题集中讲解29常见问题及解决办法代码规范问题调试技巧共性问题集中讲解使用动态SQL语句实现更新03第3章动态SQL语句<set>元素使用场景

在Hibernate框架中,如果想要更新某一个对象,就需要发送所有的字段给持久化对象,然而在实际应用中,大多数情况下都是更新某一个或几个字段。如果更新的每一条数据都要将其所有的属性都更新一遍,那么执行效率是非常差的。为了解决更新数据的效率问题,MyBatis提供了<set>元素。<set>元素主要用于更新操作,它可以在动态SQL语句前输出一个SET关键字,并将SQL语句中最后一个多余的逗号去除。<set>元素与<if>元素结合可以只更新需要更新的字段。

更新操作31<set>元素32select*fromt_customerwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>

在Hibernate中,想要更新某个对象,就需要发送所有的字段给持久化对象,这种想更新的每一条数据都要将其所有的属性都更新一遍的方法,其执行效率是非常差的。为此,在MyBatis中可以使用动态SQL中的<set>元素进行处理:<updateid="update"parameterType=“User">updatetb_user<set><iftest="username!=nullandusername!=''">username=#{username},</if><iftest="jobs!=nullandjobs!=''">jobs=#{jobs},</if></set>whereid=#{id}</update>使用<set>和<if>元素对username和jobs进行更新判断,并动态组装SQL。这样就只需要传入想要更新的字段即可<set>元素字段非空

在映射文件中使用<set>元素和<if>元素组合进行update语句动态SQL组装时,如果<set>元素内包含的内容都为空,则会出现SQL语法错误。因此,在使用<set>元素进行字段信息更新时,要确保传入的更新字段不能都为空。更新操作33set34更新用户表数据时,若某个参数为null时,会导致更新错误正确结果若某个参数为null,则不需要更新,保持数据库原值原因SQL语句如何处理ifset演示示例:改造用户表的修改操作-if+set指导注意技能训练—改造供应商表修改操作(if+set)35需求说明改造供应商表的修改功能,使用动态SQL完善此功能修改SQL语句–使用if+set组合完成时间:15分钟练习指导共性问题集中讲解36常见问题及解决办法代码规范问题调试技巧共性问题集中讲解使用<trim>元素更新

除了使用<set>元素外,还可以通过<trim>元素来实现更新操作。其中,<trim>元素的prefix属性指定要添加的<trim>元素所包含内容的前缀为set,suffixOverrides属性指定去除的<trim>元素所包含内容的后缀为逗号。更新操作37trim38if+trim使用if+trim替代if+set进行更新用户表数据,效果一样演示示例:改造用户表的修改操作-if+trim<updateid="modify"parameterType="User">updatetb_user<trimprefix="set"suffixOverrides=","suffix="whereid=#{id}"> <iftest="userCode!=null">userCode=#{userCode},</if> <iftest="userName!=null">userCode=#{userName},</if> <iftest="userPassword!=null">userPassword=#{userPassword},</if></trim></update>示例改造供应商表修改操作(if+trim)39需求说明改造供应商表的修改功能,使用动态SQL完善此功能修改SQL语句–使用if+trim组合完成时间:15分钟练习指导共性问题集中讲解40常见问题及解决办法代码规范问题调试技巧共性问题集中讲解使用<foreach>元素实现复杂查询04第3章动态SQL语句<foreach>元素42select*fromt_customerwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>

在一个客户表中有1000条数据,现在需要将id值小于100的客户信息全部查询出来,这要怎么做呢?假设如下需求:一条一条的查询1在Java中用for循环查询2那如果要查询1000条数据呢,岂不是很累?考虑过N条查询语句时的查询效率了吗?<foreach>元素43foreach迭代一个集合,通常用于in条件属性itemindexcollection:必须指定listarraymap-keyopenseparatorclose<foreach>元素的属性

44属性说明item

表示集合中每一个元素进行迭代时的别名。该属性为必选。index在List和数组中,index是元素的序号,在Map中,index是元素的key。该属性可选。open

表示foreach语句代码的开始符号,一般和close=“)”合用。常用在in条件语句中。该属性可选。separator

表示元素之间的分隔符,例如,在条件语句中,separator=“,”会自动在元素中间用“,”隔开,避免手动输入逗号导致SQL错误,错误示例如in(1,2,)。该属性可选。close表示foreach语句代码的关闭符号,一般和open="("合用。常用在in条件语句中。该属性可选。collection用于指定遍历参数的类型。注意,该属性必须指定,不同情况下,该属性的值是不一样的。

<foreach>元素45需求说明:指定用户角色(1-n个),获取这些用户角色下的用户列表信息查询SQL语句含有in条件使用foreach实现参数:用户角色列表参数类型:数组演示示例:获取指定用户角色下用户列表-foreach_array分析select*fromtb_user whereuserRolein(参数1,参数2,参数3…);<foreach>元素46

针对上述需求,理想的解决方法就是使用MyBatis中动态SQL的<foreach>元素进行处理。其基本使用示例如下所示:<selectid="findUserByIds"parameterType="List"resultType=“User">select*fromtb_userwhereidin<foreachitem="id"index="index"collection="list"open="("separator=","close=")">#{id}</foreach></select><foreach>元素47

关于上述示例中<foreach>元素中使用的几种属性的描述具体如下:<foreach>主要属性item:配置的是循环中当前的元素。collection:配置的list是传递过来的参数类型(首字母小写),它可以是一个array、list(或collection)、Map集合的键、POJO包装类中数组或集合类型的属性名等。index:配置的是当前元素在集合的位置下标。separator:配置的是各个元素的间隔符。open和close:配置的是以什么符号将这些集合元素包装起来。在遍历参数时,<collection>属性的值是必须指定的。不同情况下,该属性的取值也是不一样的,主要有以下三种情况。List类型

若入参为单参数且参数类型是一个List,collection属性值为list。数组类型若入参为单参数且参数类型是一个数组,collection属性值为array。Map类型

若传入参数为多参数,就需要把参数封装为一个Map进行处理,collection属性值为Map。<collection>属性的取值48<foreach>元素49

在使用<foreach>时最关键也是最容易出错的就是collection属性,该属性是必须指定的,而且在不同情况下,该属性的值是不一样的。主要有以下3种情况:如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array和list(或collection)。1如果传入的参数是多个的时候,就需要把它们封装成一个Map了,当然单参数也可以封装成Map集合,这时候collection属性值就为Map的键。2如果传入的参数是POJO包装类的时候,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。3<foreach>元素50需求说明:改造上一个演示示例,使用foreach实现,参数类型改为List演示示例:获取指定用户角色下用户列表-foreach_list获取指定供应商列表下的订单列表51需求说明指定供应商列表(1-n个),获取这些供应商下的订单列表信息要求使用foreach实现,参数类型为数组完成之后,把参数类型改为List实现此功能完成时间:20分钟练习共性问题集中讲解52常见问题及解决办法代码规范问题调试技巧共性问题集中讲解<foreach>元素53需求说明:在上一个演示示例中,增加一个参数:gender,要求查询出指定性别和用户角色列表下的用户列表多参数封装成Map单参数也可封装成Map吗?演示示例:获取多参数下用户列表-foreach_map分析问题思考获取多参数下的订单列表54需求说明:根据订单编码(模糊查询),指定供应商列表(1-n个),获取相应的订单列表信息多参数封装成Map完成时间:30分钟练习指导共性问题集中讲解55常见问题及解决办法代码规范问题调试技巧共性问题集中讲解使用<bind>元素实现SQL语句拼接05第3章动态SQL语句<bind>元素57

还记得入门案例中模糊查询的SQL语句么?select*fromtb_userwhereusernamelike'%${value}%'上述SQL语句有什么不妥?2如果使用“${}”进行字符串拼接,则无法防止SQL注入问题;如果改用concat函数进行拼接,则只针对MySQL数据库有效;3如果改用“||”进行字符串拼接,则只针对Oracle数据库有效。1小提示:这样,映射文件中的SQL就要根据不同的情况提供不同形式的实现,这显然是比较麻烦的,且不利于项目的移植。为了减少这种麻烦,就可以使用MyBatis的<bind>元素来解决这一问题。<bind>元素58MyBatis的<bind>元素可以通过OGNL表达式来创建一个上下文变量,其使用方式如下:<!--<bind>元素的使用:根据用户名模糊查询用户信息--><selectid="findUserByName"parameterType="User"resultType="User"> <!--_parameter.getUsername()也可直接写成传入的字段属性名,即username--> <bindname="pattern_username"value="'%'+_parameter.getUserName()+'%'"/> select*fromtb_user whereusernamelike#{pattern_username}</select>_parameter.getUsername()表示传递进来的参数(也可以直接写成对应的参数变量名,如username)需要的地方直接引用<bind>元素的name属性值即可本章小结

本章主要讲解了动态SQL相关知识。首先讲解了动态SQL中的元素;其次讲解了条件查询操作,包括<if>元素、<choose>元素、<when>元素、<otherwise>元素、<where>元素和<trim>元素的使用;然后讲解了更新操作;最后讲解了复杂查询操作。通过本章的学习,读者可以了解常用动态SQL元素的主要作用,并能够掌握这些元素在实际开发中的应用。在MyBatis框架中,这些动态SQL元素十分重要,熟练的掌握它们能够极大地提高开发效率。

本章小结59总结60if+setif-whereif+trimchoose(when、otherwise)foreachMyBatis-动态SQLitemidexcollectionopenseparatorcloselistarraymap本章作业✎

本章作业请简述MyBatis框架动态SQL中的主要元素及其作用。请简述MyBatis框架动态SQL中<foreach>元素collection属性的注意事项。✎预习作业不同对象之间有哪几种关联方式?MyBatis关联查询的方式有哪些?61问题及作业集中问题&课后作业62关联映射一对一一对多多对多<resultMap>元素自动映射级别第4章

MyBatis的关联映射2024/1/29学习目标/Target64了解表之间及对象之间的关联关系熟悉关联关系中的嵌套查询和嵌套结果掌握一对一、一对多和多对多关联映射的使用方法章节概述/Summary65通过前面几章介绍了MyBatis的基本用法、关联映射和动态SQL等重要知识,但这些知识只是针对单表实现进行操作的,在实际开发中,对数据库的操作常常会涉及到多张表,针对多表之间的操作,MyBatis提供了关联映射,通过关联映射可以很好地处理表与表、对象与对象之间的关联关系。此外,在实际开发中经常需要合理地利用MyBatis缓存来加快数据库查询,进而有效地提升数据库性能。本章将对MyBatis的关联映射以及MyBatis缓存机制进行详细讲解。

目录/CONTENTS关联映射多对多一对多一对一66<resultMap>元素自动映射级别14325关联映射01第4章MyBatis的关联映射为什么学习MyBatis关联关系?关联关系概述68

实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系。本章中,将对MyBatis的关联关系映射进行详细的讲解。STEP01

在关系型数据库中,表与表之间存在着三种关联映射关系,分别为一对一关系、一对多关系和多对多关系。STEP03关联映射关系关联映射的概述69一对一一个数据表中的一条记录最多可以和另一个数据表中的一条记录相关。例如,现实生活中学生与校园卡就属于一对一的关系,一个学生只能拥有一张校园卡,一张校园卡只能属于一个学生。一对多主键数据表中的一条记录可以和另外一个数据表的多条记录相关。但另外一个数据表中的记录只能与主键数据表中的某一条记录相关。例如,现实中班级与学生的关系就属于一对多的关系,一个班级可以有很多学生,但一个学生只能属于一个班级。多对多一个数据表中的一条记录可以与另外一个数据表任意数量的记录相关,另外一个数据表中的一条记录也可以与本数据表中任意数量的记录相关。例如,现实中学生与教师属于多对多的关系,一名学生可以由多名教师授课,一名教师可以为多名学生授课。关联关系概述70

在关系型数据库中,多表之间存在着三种关联关系,分别为一对一、一对多和多对多,如下图所示:一对一一对多多对多在任意一方引入对方主键作为外键;在“多”的一方,添加“一”的一方的主键作为外键;产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。关联关系概述71

在Java中,通过对象也可以进行关联关系描述,如图所示:一对一一对多多对多在本类中定义对方类型的对象,如A类中定义B类类型的属性b,B类中定义A类类型的属性a;一个A类类型对应多个B类类型的情况,需要在A类中以集合的方式引入B类类型的对象,在B类中定义A类类型的属性a;在A类中定义B类类型的集合,在B类中定义A类类型的集合。一对一02第4章MyBatis的关联映射一对一73

在现实生活中,一对一关联关系是十分常见的。例如,一个人只能有一个身份证,同时一个身份证也只会对应一个人。

那么使用MyBatis是怎么处理图中的这种一对一关联关系的呢?

在前面章节所讲解的<resultMap>元素中,包含了一个<association>子元素,MyBatis就是通过该元素来处理一对一关联关系的。一对一74

在<association>元素中,通常可以配置以下属性:property指定映射到的实体类对象属性,与表字段一一对应columnjavaType指定映射到实体对象属性的类型指定表中对应的字段select指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询fetchType指定在关联查询时是否启用延迟加载。该属性有lazy和eager两个属性值,默认值为lazy(即默认关联映射延迟加载)一对一75MyBatis加载关联关系对象主要通过两种方式:嵌套查询和嵌套结果。

嵌套查询是通过执行另外一条SQL映射语句来返回预期的复杂类型。

嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集。第一种第二种嵌套查询是在查询SQL中嵌入一个子查询SQL;嵌套结果是一个嵌套的多表查询SQL;嵌套查询会执行多条SQL语句;嵌套结果只会执行一条复杂的SQL语句;嵌套查询SQL语句编写较为简单;嵌套结果SQL语句编写比较复杂;一对一76

虽然使用嵌套查询的方式比较简单,但是嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大的消耗数据库性能并且会降低查询效率。那怎么解决这种问题呢?一对一77

使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件中的<settings>元素内进行配置,具体配置方式如下:多学一招:MyBatis延迟加载的配置<settings><settingname="lazyLoadingEnabled"value="true"/><settingname="aggressiveLazyLoading"value="false"/></settings>

在映射文件中,<association>元素和<collection>元素中都已默认配置了延迟加载属性,即默认属性fetchType="lazy"(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无需在映射文件中再做配置。一对一78

使用<association>元素进行一对一关联映射非常简单,只需要参考如下两种示例配置即可。<resultMaptype="IdCard"id="IdCardById"> <idproperty="id"column="id"/> <resultproperty="userName"column="userName"/> <!--一对一:association使用select属性引入另外一条SQL语句--> <associationproperty="user"column="uid"javaType="User"

select="cn.dsscm.dao.UserMapper.findUserById"/></resultMap>算术运算符逻辑运算符<resultMaptype="IdCard"id="userRoleResult2"> <idproperty="id"column="id"/> <resultproperty="code"column="code"/> <associationproperty="user"javaType="User"> <idproperty="id"column="cid"/> <resultproperty="userName"column="userName"/> </association></resultMap>嵌套的子查询类属性类属性表字段表字段关联属性类型方法2:嵌套结果方法1:嵌套查询resultMap79resultMap属性id:resultMap的唯一标识type:Java实体类resultMap子元素id一般对应数据库中该行的主键id,设置此项可提高MyBatis性能result映射到JavaBean的某个“简单类型”属性association映射到JavaBean的某个“复杂类型”属性,比如JavaBean类collection映射到JavaBean的某个“复杂类型”属性,比如集合resultMap80association复杂的类型关联,一对一内部嵌套映射一个嵌套JavaBean属性属性property:映射数据库列的实体对象的属性javaType:完整Java类名或者别名resultMap:引用外部resultMap子元素idresultproperty:映射数据库列的实体对象的属性column:数据库列名或者别名用户和身份证间关联-1嵌套查询

<!--嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型--><selectid="findCodeById"parameterType="Integer"resultMap="IdCardById"> SELECT*FROMtb_idcardWHEREid=#{id}</select><resultMaptype="IdCard"id="IdCardById"> <idproperty="id"column="id"/> <resultproperty="userName"column="userName"/> <!--一对一:association使用select属性引入另外一条SQL语句--> <associationproperty="user"column="uid"javaType="User"

select="cn.dsscm.dao.UserMapper.findUserById"/></resultMap><!--根据id查询用户信息--><selectid="findUserById"parameterType="Integer"resultType="User"> SELECT*fromtb_userwhereid=#{id}</select>81用户和身份证间关联-2嵌套结果<!--根据roleId获取用户列表associationstart--><resultMaptype="IdCard"id="userRoleResult2"> <idproperty="id"column="id"/> <resultproperty="code"column="code"/> <associationproperty="user"javaType="User"> <idproperty="id"column="cid"/> <resultproperty="userName"column="userName"/> </association></resultMap><selectid="findCodeById2"parameterType="Integer"resultMap="userRoleResult2"> SELECTu.*,c.idcid,c.code FROMtb_useru,tb_idcardc WHEREu.id=c.uid ANDc.uid=#{uid}</select>82用户和用户角色关联-183嵌套结果<!--根据roleId获取用户列表associationstart--><resultMaptype="User"id="userRoleResult"> <idproperty="id"column="id"/> <resultproperty="userCode"column="userCode"/> <resultproperty="userName"column="userName"/> <resultproperty="userRole"column="userRole"/>

<associationproperty="role"javaType="Role"> <idproperty="id"column="r_id"/> <resultproperty="roleCode"column="roleCode"/> <resultproperty="roleName"column="roleName"/> </association></resultMap><selectid="getUserListByRoleId"parameterType="Integer"resultMap="userRoleResult"> selectu.*,r.idasr_id,r.roleCode,r.roleName fromtb_useru,tb_roler whereu.userRole=#{userRole}andu.userRole=r.id</select>用户和用户角色关联-284嵌套结果resultMap实现association的结果映射<!--根据roleId获取用户列表associationstart--><resultMaptype="User"id="userRoleResult2"> <idproperty="id"column="id"/> <resultproperty="userCode"column="userCode"/> <resultproperty="userName"column="userName"/> <resultproperty="userRole"column="userRole"/> <associationproperty="role"javaType="Role"resultMap="roleResult"/></resultMap><resultMaptype="Role"id="roleResult"> <idproperty="id"column="r_id"/> <resultproperty="roleCode"column="roleCode"/> <resultproperty="roleName"column="roleName"/></resultMap><selectid="getUserListByRoleId2"parameterType="Integer"resultMap="userRoleResult2"> selectu.*,r.idasr_id,r.roleCode,r.roleNamefromtb_useru,tb_roler whereu.userRole=#{userRole}andu.userRole=r.id</select>实现订单表的查询(association)85需求说明:实现按条件查询订单表,查询条件如下:商品名称(模糊查询)供应商(供应商id)是否付款查询结果列显示:订单编码、商品名称、供应商编码、供应商名称、供应商联系人、供应商联系电话、订单金额、是否付款resultMap中使用association子元素完成内部嵌套修改Bill.java,增加复杂类型属性:Provider编写SQL查询语句(连表查询)创建resultMap-自定义映射结果,并在select中引用完成时间:20分钟练习指导共性问题集中讲解86常见问题及解决办法代码规范问题调试技巧共性问题集中讲解一对多03第4章MyBatis的关联映射一对多88

开发人员接触更多的关联关系是一对多(或多对一)。例如,一个用户可以有多个订单,同时多个订单归一个用户所有。

那么使用MyBatis是怎么处理这种一对多关联关系的呢?

在前面章节所讲解的<resultMap>元素中,包含了一个<collection>子元素,MyBatis就是通过该元素来处理一对多关联关系的。一对多89ofTypeofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型。

<collection>子元素的属性大部分与<association>元素相同,但其还包含一个特殊属性--ofType。一对多90<collection>元素的使用也非常简单,同样可以参考如下两种示例进行配置,具体代码如下:方法1:嵌套查询<collectionproperty="users"column="id"ofType="User"select="cn.dsscm.dao.selectUsers"/>方法2:嵌套结果<collectionproperty="users"ofType="User"> <idproperty="id"column="id"/> <resultproperty="userCode"column="userCode"/> <resultproperty="userName"column="userName"/> <resultproperty="userRole"column="userRole"/></collection>嵌套的子查询类属性类属性表字段表字段关联的集合类属性类型resultMap91collection复杂类型集合,一对多内部嵌套映射一个嵌套结果集到一个列表属性property:映射数据库列的实体对象的属性ofType:完整Java类名或者别名(集合所包括的类型)resultMap:引用外部resultMap子元素idresultproperty:映射数据库列的实体对象的属性column:数据库列名或者别名用户角色关联用户信息92嵌套结果<resultMaptype="Role"id="rolelist"><idproperty="id"column="rid"/><resultproperty="roleName"column="roleName"/><collectionproperty="users"ofType="User"><idproperty="id"column="id"/><resultproperty="userCode"column="userCode"/><resultproperty="userName"column="userName"/><resultproperty="userRole"column="userRole"/></collection></resultMap><selectid="getRole"resultMap="rolelist"> SELECTr.idrid,r.roleName,r.roleCode,u.* FROMtb_roler,tb_useru WHEREr.id=u.userRole <iftest="id>0">ANDr.id=#{id}</if></select>publicclassRole{ ……

privateList<User>users;}商品类型关联商品信息93嵌套结果<resultMaptype="ProductCategory"id="productlist"><idproperty="id"column="cid"/><resultproperty="name"column="cname"/><collectionproperty="products"ofType="Product"><idproperty="id"column="id"/><resultproperty="name"column="name"/><resultproperty="price"column="price"/><resultproperty="stock"column="stock"/></collection></resultMap><selectid="getProduct"resultMap="productlist"> SELECTc.idcid,cname,p.* FROMtb_product_categoryc,tb_productp WHEREc.id=p.categoryLevel1Id <iftest="id>0">ANDc.id=#{id}</if> ORDERBYc.id</select>publicclassProductCategoryimplementsSerializable{ ……

privateList<Product>products; //省略getter和setter方法}resultMap94如何提高结果映射的可重用性?collection的resultMap属性分析问题获取供应商及其订单列表(collection)95需求说明:根据指定的供应商(id)查询出其相关信息以及其下所有的订单列表查询结果列显示:供应商id、供应商编码、供应商名称、供应商联系人、供应商联系电话、订单列表信息(订单编码、商品名称、订单金额、是否付款)resultMap中使用collection子元素完成内部嵌套修改Provider.java,增加集合类型属性:List<Bill>billList编写SQL查询语句(连表查询)创建resultMap-自定义映射结果,并在select中引用完成时间:20分钟练习指导共性问题集中讲解96常见问题及解决办法代码规范问题调试技巧共性问题集中讲解多对多04第4章MyBatis的关联映射多对多98

在实际项目开发中,多对多的关联关系也是非常常见的。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多个订单。

在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。销售订单关联订购商品信息-199嵌套查询

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论