• SSM - Springboot - MyBatis-Plus 全栈体系(十六)


    第三章 MyBatis

    三、MyBatis 多表映射

    2. 对一映射

    2.1 需求说明
    • 根据 ID 查询订单,以及订单关联的用户的信息!
    2.2 OrderMapper 接口
    public interface OrderMapper {
      Order selectOrderWithCustomer(Integer orderId);
    }
    
    • 1
    • 2
    • 3
    2.3 OrderMapper.xml 配置文件
    
    
    
    <resultMap id="selectOrderWithCustomerResultMap" type="order">
    
      
      <id column="order_id" property="orderId"/>
    
      <result column="order_name" property="orderName"/>
    
      
      
      
      <association property="customer" javaType="customer">
    
        
        <id column="customer_id" property="customerId"/>
        <result column="customer_name" property="customerName"/>
    
      association>
    
    resultMap>
    
    
    <select id="selectOrderWithCustomer" resultMap="selectOrderWithCustomerResultMap">
    
      SELECT order_id,order_name,c.customer_id,customer_name
      FROM t_order o
      LEFT JOIN t_customer c
      ON o.customer_id=c.customer_id
      WHERE o.order_id=#{orderId}
    
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 对应关系可以参考下图:

    在这里插入图片描述

    2.4 Mybatis 全局注册 Mapper 文件
    
    <mappers>
    
      
      <mapper resource="mappers/OrderMapper.xml"/>
    
    mappers>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.5 junit 测试程序
    @Slf4j
    public class MyBatisTest {
    
        private SqlSession session;
        // junit会在每一个@Test方法前执行@BeforeEach方法
    
        @BeforeEach
        public void init() throws IOException {
            session = new SqlSessionFactoryBuilder()
                    .build(
                            Resources.getResourceAsStream("mybatis-config.xml"))
                    .openSession();
        }
    
        @Test
        public void testRelationshipToOne() {
    
          OrderMapper orderMapper = session.getMapper(OrderMapper.class);
          // 查询Order对象,检查是否同时查询了关联的Customer对象
          Order order = orderMapper.selectOrderWithCustomer(2);
          log.info("order = " + order);
    
        }
    
        // junit会在每一个@Test方法后执行@@AfterEach方法
        @AfterEach
        public void clear() {
            session.commit();
            session.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    2.6 关键词
    • 在“对一”关联关系中,我们的配置比较多,但是关键词就只有:associationjavaType

    3. 对多映射

    3.1 需求说明
    • 查询客户和客户关联的订单信息!
    3.2 CustomerMapper 接口
    public interface CustomerMapper {
    
      Customer selectCustomerWithOrderList(Integer customerId);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    3.3 CustomerMapper.xml 文件
    <!-- 配置resultMap实现从CustomerOrderList的“对多”关联关系 -->
    <resultMap id="selectCustomerWithOrderListResultMap"
    
      type="customer">
    
      <!-- 映射Customer本身的属性 -->
      <id column="customer_id" property="customerId"/>
    
      <result column="customer_name" property="customerName"/>
    
      <!-- collection标签:映射“对多”的关联关系 -->
      <!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
      <!-- ofType属性:集合属性中元素的类型 -->
      <collection property="orderList" ofType="order">
    
        <!-- 映射Order的属性 -->
        <id column="order_id" property="orderId"/>
    
        <result column="order_name" property="orderName"/>
    
      </collection>
    
    </resultMap>
    
    <!-- Customer selectCustomerWithOrderList(Integer customerId); -->
    <select id="selectCustomerWithOrderList" resultMap="selectCustomerWithOrderListResultMap">
      SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
      FROM t_customer c
      LEFT JOIN t_order o
      ON c.customer_id=o.customer_id
      WHERE c.customer_id=#{customerId}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 对应关系可以参考下图:

    在这里插入图片描述

    3.4 Mybatis 全局注册 Mapper 文件
    
    <mappers>
      
      <mapper resource="mappers/OrderMapper.xml"/>
      <mapper resource="mappers/CustomerMapper.xml"/>
    mappers>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    3.5 junit 测试程序
    @Test
    public void testRelationshipToMulti() {
    
      CustomerMapper customerMapper = session.getMapper(CustomerMapper.class);
      // 查询Customer对象同时将关联的Order集合查询出来
      Customer customer = customerMapper.selectCustomerWithOrderList(1);
      log.info("customer.getCustomerId() = " + customer.getCustomerId());
      log.info("customer.getCustomerName() = " + customer.getCustomerName());
      List<Order> orderList = customer.getOrderList();
      for (Order order : orderList) {
        log.info("order = " + order);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    3.6 关键词
    • 在“对多”关联关系中,同样有很多配置,但是提炼出来最关键的就是:“collection”和“ofType”

    4. 多表映射总结

    4.1 多表映射优化
    setting 属性属性含义可选值默认值
    autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL
    • 我们可以将 autoMappingBehavior 设置为 full,进行多表 resultMap 映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的 result 标签

    • 修改 mybatis-sconfig.xml:

    
    <setting name="autoMappingBehavior" value="FULL"/>
    
    • 1
    • 2
    • 修改 teacherMapper.xml
    <resultMap id="teacherMap" type="teacher">
        <id property="tId" column="t_id" />
        
    
        <collection property="students" ofType="student" >
            <id property="sId" column="s_id" />
    
        collection>
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    4.2 多表映射总结
    关联关系配置项关键词所在配置文件和具体位置
    对一association 标签/javaType 属性/property 属性Mapper 配置文件中的 resultMap 标签内
    对多collection 标签/ofType 属性/property 属性Mapper 配置文件中的 resultMap 标签内

    四、MyBatis 动态语句

    1. 动态语句需求和简介

    • 经常遇到很多按照很多查询条件进行查询的情况,比如智联招聘的职位搜索等。其中经常出现很多条件不取值的情况,在后台应该如何完成最终的 SQL 语句呢?

    在这里插入图片描述

    • 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
    • 使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
    • 如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

    2. if 和 where 标签

    • 使用动态 SQL 最常见情景是根据条件包含 where / if 子句的一部分。比如:
    
    <select id="selectEmployeeByCondition" resultType="employee">
        select emp_id,emp_name,emp_salary from t_emp
        
        <where>
            
            
            <if test="empName != null">
                
                or emp_name=#{empName}
            if>
            <if test="empSalary > 2000">
                or emp_salary>#{empSalary}
            if>
            
        where>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3. set 标签

    
    <update id="updateEmployeeDynamic">
        update t_emp
        
        
        <set>
            <if test="empName != null">
                emp_name=#{empName},
            if>
            <if test="empSalary < 3000">
                emp_salary=#{empSalary},
            if>
        set>
        where emp_id=#{empId}
        
    update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4. trim 标签(了解)

    • 使用 trim 标签控制条件部分两端是否包含某些字符

      • prefix 属性:指定要动态添加的前缀
      • suffix 属性:指定要动态添加的后缀
      • prefixOverrides 属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
      • suffixOverrides 属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
    
    <select id="selectEmployeeByConditionByTrim" resultType="com.atguigu.mybatis.entity.Employee">
        select emp_id,emp_name,emp_age,emp_salary,emp_gender
        from t_emp
    
        
        
        
        
        
        <trim prefix="where" suffixOverrides="and|or">
            <if test="empName != null">
                emp_name=#{empName} and
            if>
            <if test="empSalary > 3000">
                emp_salary>#{empSalary} and
            if>
            <if test="empAge <= 20">
                emp_age=#{empAge} or
            if>
            <if test="empGender=='male'">
                emp_gender=#{empGender}
            if>
        trim>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    5. choose / when / otherwise 标签

    • 在多个分支条件中,仅执行一个。

      • 从上到下依次执行条件判断
      • 遇到的第一个满足条件的分支会被采纳
      • 被采纳分支后面的分支都将不被考虑
      • 如果所有的 when 分支都不满足,那么就执行 otherwise 分支
    
    <select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
        select emp_id,emp_name,emp_salary from t_emp
        where
        <choose>
            <when test="empName != null">emp_name=#{empName}when>
            <when test="empSalary < 3000">emp_salary < 3000when>
            <otherwise>1=1otherwise>
        choose>
    
        
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    6. foreach 标签

    6.1 基本用法
    • 用批量插入举例
    
    <foreach collection="empList" item="emp" separator="," open="values" index="myIndex">
        
        (#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
    foreach>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    6.2 批量更新时需要注意
    • 上面批量插入的例子本质上是一条 SQL 语句,而实现批量更新则需要多条 SQL 语句拼起来,用分号分开。也就是一次性发送多条 SQL 语句让数据库执行。此时需要在数据库连接信息的 URL 地址中设置:
    alex.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true
    
    • 1
    • 对应的 foreach 标签如下:
    
    <update id="updateEmployeeBatch">
        <foreach collection="empList" item="emp" separator=";">
            update t_emp set emp_name=#{emp.empName} where emp_id=#{emp.empId}
        foreach>
    update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    6.3 关于 foreach 标签的 collection 属性
    • 如果没有给接口中 List 类型的参数使用@Param 注解指定一个具体的名字,那么在 collection 属性中默认可以使用 collection 或 list 来引用这个 list 集合。这一点可以通过异常信息看出来:
    Parameter 'empList' not found. Available parameters are [arg0, collection, list]
    
    • 1
    • 在实际开发中,为了避免隐晦的表达造成一定的误会,建议使用@Param 注解明确声明变量的名称,然后在 foreach 标签的 collection 属性中按照@Param 注解指定的名称来引用传入的参数。

    7. sql 片段

    7.1 抽取重复的 SQL 片段
    
    <sql id="mySelectSql">
        select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
    sql>
    
    • 1
    • 2
    • 3
    • 4
    7.2 引用已抽取的 SQL 片段
    
    <include refid="mySelectSql"/>
    
    • 1
    • 2
  • 相关阅读:
    对GROUP BY的增强
    Arouter源码系列之拦截器原理详解
    FineReport数据图表制作-标签控件
    推荐一本程序员、软件开发人员职业生涯指南的书
    Springboot快速开发-书本信息管理系统(项目源码)
    汽车蓄电池低压报警设计
    【网络篇】如何在服务器之间建立互信
    APS智能排产助力印染行业进行精细化管理
    数据库复习题带答案
    windows 2016 故障转移集群 副节点报错 群集网络名称资源“群集名称”注册一个或多个相关联的 DNS 名称失败
  • 原文地址:https://blog.csdn.net/sgsgkxkx/article/details/133499371