第三章 MyBatis关联对象查询

1. Mapper接口的传参

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

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

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

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

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

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

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

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

1.3 为方法参数设置别名

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

List<StudentInfo> studentList1(@Param("studentId") Integer studentId,
                                   @Param("classId") Integer classId);
<select id="studentList1" resultMap="studentMap">
        select studentId,name,sex,birthday,province,s.classId,
               c.classId,c.className
        from studentInfo s join classInfo c
        on s.classId = c.classId
        <where>
            <if test="studentId!=null and studentId!=''">
                and studentId &gt; #{studentId}
            </if>
            <if test="classId!=null and classId!= ''">
                and s.classId = #{classId}
            </if>
        </where>
    </select>

1.4 传入对象类型的参数

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

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

1.5 #{} 和 ${} 区别

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

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

2. resultType和resultMap的使用 

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

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

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

2.1 一对一查询的配置

        一个学生对应一个班级;

@Data
public class StudentInfo {
    private Integer studentId;
    private String name;
    private String sex;
    private Date birthday;
    private String province;
    private Integer classId;

    private ClassInfo classInfo;
}

sql: 

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

2.2 一对多的配置

        一个班级对应多个学生;

@Data
public class ClassInfo {
    private Integer classId;
    private String className;

    private List<StudentInfo> studentList;
}

 sql:

    <resultMap id="classMap" type="classInfo" autoMapping="true">
        <!--必须配置主键列-->
        <id property="classId" column="classId"/>
        <collection property="studentList" ofType="studentInfo" autoMapping="true">

        </collection>
    </resultMap>
    <select id="classList" resultMap="classMap">
        select studentId,name,sex,birthday,province,s.classId,
               c.classId,c.className
        from studentInfo s join classInfo c
        on s.classId = c.classId
    </select>
collection 标签
属性名称作用
property对象属性名称
ofType对象属性类型
column所对应的外键字段名称
select使用另一个查询封装结果

3. MyBatis 的动态SQL

        使用动态sql标签

3.1 if

        条件判断,动态拼接sql;

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

3.2 where

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

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

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

    <select id="studentList1" resultMap="studentMap">
        select studentId,name,sex,birthday,province,s.classId,
               c.classId,c.className
        from studentInfo s join classInfo c
        on s.classId = c.classId
        <where>
            <if test="studentId!=null and studentId!=''">
                and studentId &gt; #{studentId}
            </if>
            <if test="classId!=null and classId!= ''">
                and s.classId = #{classId}
            </if>
        </where>
    </select>

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

特殊符号替换方案
特殊符号转义序列
<&lt;
<=&lt;=
>&gt;
>=&gt;=
&&amp;
'&apos;
"&quot;

 备用方式:

<![CDATA[

含有特殊符号的代码

>

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属性指定
    <update id="updateStu" parameterType="StudentInfo">
        update studentInfo
        <set>
            <if test="name != null and name !=''">
                name = #{name},
            </if>
            <if test="sex!=null and sex !=''">
                sex = #{sex},
            </if>
        </set>
        where studentId = #{studentId}
    </update>

3.4 foreach

        使用循环生成sql语句;

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

3.5 choose(when,otherwise)

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

    <select id="listByCon" resultType="StudentInfo">
        select * from studentInfo
        <where>
            <choose>
                <when test="name != null and name != ''">
                    name = #{name}
                </when>
                <when test="sex !=null and sex != ''">
                    sex = #{sex}
                </when>
                <otherwise>
                    studentId = 1
                </otherwise>
            </choose>
        </where>
    </select>

3.6 返回自动增长的主键

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

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

3.7 sql标签定义通用sql片段

    <sql id="stuSql">
        select studentId,name,sex,birthday,province,s.classId,
               c.classId,c.className
        from studentInfo s join classInfo c
        on s.classId = c.classId
    </sql>
    <select id="studentList" resultMap="studentMap">
        <include refid="stuSql"></include>
    </select>

4. 延迟加载(懒加载)

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

嵌套查询:

    <!--goods-->
    <resultMap id="goodsMap2" type="Goods" autoMapping="true">
        <id property="goodsId" column="goods_id"/>
        <association property="category" 
                     javaType="Category" 
                     column="category_id" 
                     select="com.mapper.CategoryMapper.category">
        </association>
    </resultMap>
    <sql id="colSql2">
        goods_id,goods_name,price,produce_date,address,category_id
    </sql>
    <select id="goodsList2" resultMap="goodsMap2">
        select
        <include refid="colSql2"></include>
        from goods
    </select>

    <!--category-->
    <select id="category" resultType="category">
        select category_id,category_name
        from category
        where category_id = #{categroy_id}
    </select>

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

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

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

MyBatis关联查询加载时机:

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

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

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

4.1 MyBatis延迟加载实现方式

 4.1.1 全局延迟

①直接加载(默认)

        <setting name="lazyLoadingEnabled" value="false"/>
        <setting name="aggressiveLazyLoading" value="false"/>

②侵入式延迟:

        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="true"/>

效果:

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

 ③深度延迟:

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

 4.1.2 部分延迟

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

        lazy:(深度)延迟加载

        eager:立即加载

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

    <resultMap id="goodsMap2" type="Goods" autoMapping="true">
        <id property="goodsId" column="goods_id"/>
        <association property="category"
                     javaType="Category"
                     column="category_id"
                     select="com.mapper.CategoryMapper.category"
                     fetchType="eager">
        </association>
    </resultMap>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值