• 第三章 MyBatis关联对象查询


    1. Mapper接口的传参

            在mapper文件中,每个sql语句的id都是唯一的,所以在mapper接口中定义重载方法没有意义。

    1.1 接口方法传一个基本类型的参数

            当接口方法有一个基本类型参数时,mapper文件中的sql语句中可以使用  #{任意名称}  引用这个参数;

    List list1(Integer stuId);
    1. <select id="list1" resultType="StudentInfo">
    2. select * from studentInfo
    3. where studentId = #{xxx}
    4. </select>

    1.2 接口方法传多个基本类型参数

            当接口方法中有多个参数时, mapper不能直接使用参数名引用参数,可以使用 #{arg0},

    #{arg1}这种特定的参数名来依次传参,或者用 #{param1},#{param2};

    List list2(Integer stuId,String name);
    1. <select id="list2" resultType="StudentInfo">
    2. select * from studentInfo
    3. where studentId = #{arg0} and name = #{arg1}
    4. </select>

    1.3 为方法参数设置别名

            对于多个参数使用上中方式不够直观,可以通过 @Param注解  为接口方法的参数设置别名,mybatis会自动将多个参数数据封装到Map对象中;

    1. List studentList1(@Param("studentId") Integer studentId,
    2. @Param("classId") Integer classId);
    1. <select id="studentList1" resultMap="studentMap">
    2. select studentId,name,sex,birthday,province,s.classId,
    3. c.classId,c.className
    4. from studentInfo s join classInfo c
    5. on s.classId = c.classId
    6. <where>
    7. <if test="studentId!=null and studentId!=''">
    8. and studentId &gt; #{studentId}
    9. </if>
    10. <if test="classId!=null and classId!= ''">
    11. and s.classId = #{classId}
    12. </if>
    13. </where>
    14. </select>

    1.4 传入对象类型的参数

            方法参数用对象封装,在mapper文件中可以直接引用对象属性;

     List listByStu(StudentInfo studentInfo);
    
    1. <select id="listByStudent" resultType="StudentMap" parameterType="StudentInfo">
    2. select * from studentInfo
    3. where sex = #{sex} and name like concat("%",#{name},"%")
    4. </select>

    1.5 #{} 和 ${} 区别

    #{ }:是一个参数占位符,mybatis默认使用PreparedStatement 来执行sql语句,#{} 等价于             占位符 ?;

    ${ }:用字符串拼接的方式,拼接sql语句,当方法参数只有一个值的时候,同时没有设置               @Param 注解时可以使用 ${value} 来引用参数,同时不安全,sql注入。

    2. resultType和resultMap的使用 

            对于查询而言,除了使用resultType指定返回记录类型,也可以使用resultMap进行查询结果的映射。

    resultType:查询结果是单表数据(单一实体),或者插叙的列名和实体属性能一一对应,一般                      用于简单结果集的映射配置;

    resultMap:查询是多表数据(有多个实体),或者查询的列名和实体属性不能对应,一般用于                      复杂结果集的映射配置。

    2.1 一对一查询的配置

            一个学生对应一个班级;

    1. @Data
    2. public class StudentInfo {
    3. private Integer studentId;
    4. private String name;
    5. private String sex;
    6. private Date birthday;
    7. private String province;
    8. private Integer classId;
    9. private ClassInfo classInfo;
    10. }

    sql: 

    1. <resultMap id="studentMap" type="StudentInfo" autoMapping="true">
    2. <association property="classInfo" javaType="ClassInfo" autoMapping="true"/>
    3. </resultMap>
    4. <select id="studentList" resultMap="studentMap">
    5. select studentId,name,sex,birthday,province,s.classId,
    6. c.classId,c.className
    7. from studentInfo s join classInfo c
    8. on s.classId = c.classId
    9. </select>
    association可用的属性
    属性名称作用
    property对象属性名称
    javaType对象属性的类型
    column所对应的外键字段名称
    select使用另一个查询封装结果

    2.2 一对多的配置

            一个班级对应多个学生;

    1. @Data
    2. public class ClassInfo {
    3. private Integer classId;
    4. private String className;
    5. private List studentList;
    6. }

     sql:

    1. <resultMap id="classMap" type="classInfo" autoMapping="true">
    2. <!--必须配置主键列-->
    3. <id property="classId" column="classId"/>
    4. <collection property="studentList" ofType="studentInfo" autoMapping="true">
    5. </collection>
    6. </resultMap>
    7. <select id="classList" resultMap="classMap">
    8. select studentId,name,sex,birthday,province,s.classId,
    9. c.classId,c.className
    10. from studentInfo s join classInfo c
    11. on s.classId = c.classId
    12. </select>
    collection 标签
    属性名称作用
    property对象属性名称
    ofType对象属性类型
    column所对应的外键字段名称
    select使用另一个查询封装结果

    3. MyBatis 的动态SQL

            使用动态sql标签

    3.1 if

            条件判断,动态拼接sql;

    一般用于非空验证,不满足条件,if标签里面的代码就不会执行。

    3.2 where

             一般和if结合使用,根据参数动态拼接sql,特点:

    ①当需要拼接条件时,根据参数值动态拼接sql;

    ②自动去除第一个条件前面的and关键字。

    1. <select id="studentList1" resultMap="studentMap">
    2. select studentId,name,sex,birthday,province,s.classId,
    3. c.classId,c.className
    4. from studentInfo s join classInfo c
    5. on s.classId = c.classId
    6. <where>
    7. <if test="studentId!=null and studentId!=''">
    8. and studentId &gt; #{studentId}
    9. </if>
    10. <if test="classId!=null and classId!= ''">
    11. and s.classId = #{classId}
    12. </if>
    13. </where>
    14. </select>

     此外,在xml文件中尽量避免直接写 >,<,& 等;

    特殊符号替换方案
    特殊符号转义序列
    <<
    <=<=
    >>
    >=>=
    &&
    ''
    ""

     备用方式:

    含有特殊符号的代码

    >

    3.3 trim,set

            trim 标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接"where","set"以及"values("等前缀,或者添加")"等后缀,可用于选择性插入,更新,删除或者条件查询等操作。

    trim属性
    属性描述
    prefix给sql语句拼接后缀
    suffix给sql语句拼接前缀
    prefixOverides
    去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
    suffixOverides
    去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定
    1. <update id="updateStu" parameterType="StudentInfo">
    2. update studentInfo
    3. <set>
    4. <if test="name != null and name !=''">
    5. name = #{name},
    6. </if>
    7. <if test="sex!=null and sex !=''">
    8. sex = #{sex},
    9. </if>
    10. </set>
    11. where studentId = #{studentId}
    12. </update>

    3.4 foreach

            使用循环生成sql语句;

            foreach 标签可迭代任何对象(如数组、集合(list,set,map)等)和任何的字典或者数组对象传递给 foreach 作为集合参数,当使用可迭代对象或者数组时,
    index 是当前迭代的次数,
    item 的值是本次迭代获取的元素;
    当使用字典(或者 Map.Entry 对象的集合)时, index 是键, item 是值;
    collection 标签可以填( 'list','array','map')
    1. <!--传入整数数组-->
    2. <select id="listByArray" resultType="StudentInfo">
    3. select * from studentInfo
    4. where studentId in
    5. <foreach collection="array" item="data" open="(" close=")" separator=",">
    6. #{data}
    7. </foreach>
    8. </select>
    1. <!--批量插入数据-->
    2. <insert id="insertGoods" parameterType="java.util.ArrayList">
    3. insert into tb_goods(goods_name,price,produce_date,address,category_id)
    4. values
    5. <foreach collection="list" item="goods" index="index" separator=",">
    6. (#{goods.goodsName}, #{goods.price}, #{goods.produceDate}, #{goods.address}, #{goods.categoryId})
    7. </foreach>
    8. </insert>

    3.5 choose(when,otherwise)

            与switch分支语句类似,可以根据条件执行某个分支,只会执行其中的一个分支;

    1. <select id="listByCon" resultType="StudentInfo">
    2. select * from studentInfo
    3. <where>
    4. <choose>
    5. <when test="name != null and name != ''">
    6. name = #{name}
    7. </when>
    8. <when test="sex !=null and sex != ''">
    9. sex = #{sex}
    10. </when>
    11. <otherwise>
    12. studentId = 1
    13. </otherwise>
    14. </choose>
    15. </where>
    16. </select>

    3.6 返回自动增长的主键

            用于有外键关系的两个表,主表插入数据之后,需要把主表数据的自增值获取到,然后再插入从表的数据时,插入到从表的外键列中;

    useGeneratedKeys="true" 启用自增值返回的功能
    keyProperty="实体属性": 自增值填充到传入对象的那个属性中
    1. <insert id="insertStu" parameterType="StudentInfo" useGeneratedKeys="true" keyProperty="studentId">
    2. insert into studentInfo
    3. (name,sex,birthday,province)
    4. values
    5. (#{name},#{sex},#{birthday},#{province})
    6. </insert>

    3.7 sql标签定义通用sql片段

    1. <sql id="stuSql">
    2. select studentId,name,sex,birthday,province,s.classId,
    3. c.classId,c.className
    4. from studentInfo s join classInfo c
    5. on s.classId = c.classId
    6. </sql>
    7. <select id="studentList" resultMap="studentMap">
    8. <include refid="stuSql"></include>
    9. </select>

    4. 延迟加载(懒加载)

            使用嵌套查询实现多表关联,使用嵌套查询的时候会出现1+N的问题;

    嵌套查询:

    1. <!--goods-->
    2. <resultMap id="goodsMap2" type="Goods" autoMapping="true">
    3. <id property="goodsId" column="goods_id"/>
    4. <association property="category"
    5. javaType="Category"
    6. column="category_id"
    7. select="com.mapper.CategoryMapper.category">
    8. </association>
    9. </resultMap>
    10. <sql id="colSql2">
    11. goods_id,goods_name,price,produce_date,address,category_id
    12. </sql>
    13. <select id="goodsList2" resultMap="goodsMap2">
    14. select
    15. <include refid="colSql2"></include>
    16. from goods
    17. </select>
    18. <!--category-->
    19. <select id="category" resultType="category">
    20. select category_id,category_name
    21. from category
    22. where category_id = #{categroy_id}
    23. </select>

    1+N问题(查询一次商品要查询多次种类):

            可以使用延迟加载技术解决这个问题;

            延迟加载,就是再进行关联查询的时候,按照设置的延迟规则推迟对关联对象的查询;延迟加载可以有效的减少数据库的压力,延迟加载只是对有延迟设置的关联对象的推迟查询,对于主查询是直接执行sql。

    MyBatis关联查询加载时机:

    ①直接加载:执行完主对象的查询后,马上执行对关联对象的查询语句;

    ②侵入式延迟:执行完对主对象的查询后,不会执行对关联对象的查询,但当访问主对象的属性时,就会执行关联对象的查询;

    ③深度延迟:只有当真正访问关联对象的详情时,才会执行查询语句。 

    4.1 MyBatis延迟加载实现方式

     4.1.1 全局延迟

    ①直接加载(默认)

    1. <setting name="lazyLoadingEnabled" value="false"/>
    2. <setting name="aggressiveLazyLoading" value="false"/>

    ②侵入式延迟:

    1. <setting name="lazyLoadingEnabled" value="true"/>
    2. <setting name="aggressiveLazyLoading" value="true"/>

    效果:

    (访问对象属性时执行关联对象查询)

     ③深度延迟:

    (访问关联对象时执行关联查询)

     4.1.2 部分延迟

    在关联查询collection,association标签上添加fetchType属性;

            lazy:(深度)延迟加载

            eager:立即加载

    指定属性后,在映射配置中的全局配置  lazyLoadingEnabled 会被忽略。

    1. <resultMap id="goodsMap2" type="Goods" autoMapping="true">
    2. <id property="goodsId" column="goods_id"/>
    3. <association property="category"
    4. javaType="Category"
    5. column="category_id"
    6. select="com.mapper.CategoryMapper.category"
    7. fetchType="eager">
    8. association>
    9. resultMap>
  • 相关阅读:
    【力扣刷题】只出现一次的数字、多数元素、环形链表 II、两数相加
    Shiro学习2----spring boot整合(JdbcRealm)
    Leetcode刷题Day3----------链表
    springboot导入excel(POI)
    2024年腾讯云8核16G18M服务器租用价格1668元15个月
    Nginx+keepalived 高可用高性能
    【论文简述及翻译】MVSNet:Depth Inference for Unstructured Multi-view Stereo(ECCV 2018)
    3dmax中格式批量互转obj批量转fbx等等
    设计模式学习笔记(二十一)访问者模式及其实现
    什么是单链表?
  • 原文地址:https://blog.csdn.net/m0_71674778/article/details/126366033