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

第三章 MyBatis

三、MyBatis 多表映射

2. 对一映射

2.1 需求说明
  • 根据 ID 查询订单,以及订单关联的用户的信息!
2.2 OrderMapper 接口
public interface OrderMapper {
  Order selectOrderWithCustomer(Integer orderId);
}
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>
  • 对应关系可以参考下图:

SSM - Springboot - MyBatis-Plus 全栈体系(十六)_第1张图片

2.4 Mybatis 全局注册 Mapper 文件

<mappers>

  
  <mapper resource="mappers/OrderMapper.xml"/>

mappers>
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();
    }
}
2.6 关键词
  • 在“对一”关联关系中,我们的配置比较多,但是关键词就只有:associationjavaType

3. 对多映射

3.1 需求说明
  • 查询客户和客户关联的订单信息!
3.2 CustomerMapper 接口
public interface CustomerMapper {

  Customer selectCustomerWithOrderList(Integer customerId);

}
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>
  • 对应关系可以参考下图:

SSM - Springboot - MyBatis-Plus 全栈体系(十六)_第2张图片

3.4 Mybatis 全局注册 Mapper 文件

<mappers>
  
  <mapper resource="mappers/OrderMapper.xml"/>
  <mapper resource="mappers/CustomerMapper.xml"/>
mappers>
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);
  }
}
3.6 关键词
  • 在“对多”关联关系中,同样有很多配置,但是提炼出来最关键的就是:“collection”和“ofType”

4. 多表映射总结

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

  • 修改 mybatis-sconfig.xml:


<setting name="autoMappingBehavior" value="FULL"/>
  • 修改 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>
4.2 多表映射总结
关联关系 配置项关键词 所在配置文件和具体位置
对一 association 标签/javaType 属性/property 属性 Mapper 配置文件中的 resultMap 标签内
对多 collection 标签/ofType 属性/property 属性 Mapper 配置文件中的 resultMap 标签内

四、MyBatis 动态语句

1. 动态语句需求和简介

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

SSM - Springboot - MyBatis-Plus 全栈体系(十六)_第3张图片

  • 动态 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>

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>

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>

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>

6. foreach 标签

6.1 基本用法
  • 用批量插入举例

<foreach collection="empList" item="emp" separator="," open="values" index="myIndex">
    
    (#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
foreach>
6.2 批量更新时需要注意
  • 上面批量插入的例子本质上是一条 SQL 语句,而实现批量更新则需要多条 SQL 语句拼起来,用分号分开。也就是一次性发送多条 SQL 语句让数据库执行。此时需要在数据库连接信息的 URL 地址中设置:
alex.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true
  • 对应的 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>
6.3 关于 foreach 标签的 collection 属性
  • 如果没有给接口中 List 类型的参数使用@Param 注解指定一个具体的名字,那么在 collection 属性中默认可以使用 collection 或 list 来引用这个 list 集合。这一点可以通过异常信息看出来:
Parameter 'empList' not found. Available parameters are [arg0, collection, list]
  • 在实际开发中,为了避免隐晦的表达造成一定的误会,建议使用@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>
7.2 引用已抽取的 SQL 片段

<include refid="mySelectSql"/>

你可能感兴趣的:(SSM+全栈体系,spring,boot,mybatis,数据库)