三、MyBatis多表映射

三、MyBatis多表映射

1、多表映射的概念

1、思路

1、MyBatis 思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序查询需求,那就太好了,而 ResultMap 就是 MyBatis 就是完美答案。

2、图解

image-20240114162748918

2、学习目标

  • 多表查询语句使用

  • 多表结果承接实体类设计

  • 使用ResultMap完成多表结果映射

3、实体类设计方案

1、多表关系回顾

多表关系回顾:(双向查看)

  • 一对一

    夫妻关系,人和身份证号

  • 一对多| 多对一

    用户和用户的订单,锁和钥匙

  • 多对多

    老师和学生,部门和员工

2、实体类设计关系(查询):(单向查看)

1、对一

1、对一 : 夫妻一方对应另一方,订单对应用户都是对一关系

2、重点:实体类设计:对一关系下,类中只要包含单个对方对象类型属性即可!

3、例如:

public class Customer {

  private Integer customerId;
  private String customerName;

}

public class Order {

  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系

}  
2、对多

1、对多: 用户对应的订单,讲师对应的学生或者学生对应的讲师都是对多关系:

2、重点:实体类设计:对多关系下,类中只要包含对方类型集合属性即可!

3、例子

public class Customer {

  private Integer customerId;
  private String customerName;
  private List<Order> orderList;// 体现的是对多的关系
}

public class Order {

  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系

}

//查询客户和客户对应的订单集合  不要管!

3、多表结果实体类设计技巧

1、对一:属性包含对方对象

2、对多:属性包含对方对象集合

3、注意!

  • 只有真实发生多表查询时,才需要设计和修改实体类,否则不提前设计和修改实体类!

  • 无论多少张表联查,实体类设计都是两两考虑!

  • 在查询映射的时候,只需要关注本次查询相关的属性!例如:查询订单和对应的客户,就不要关注客户中的订单集合!

2、对一映射

1、需求

1、根据ID查询订单,以及订单关联的用户的信息!

2、代码实现

1、准备数据库

CREATE TABLE `t_customer` (`customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) );

CREATE TABLE `t_order` ( `order_id` INT NOT NULL AUTO_INCREMENT, `order_name` CHAR(100), `customer_id` INT, PRIMARY KEY (`order_id`) ); 

INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');

INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); 

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 = 1;

2、准备实体类

package com.atgui.pojo;

import lombok.Data;

@Data
public class Order {

    private Integer orderId;

    private String orderName;

    private Integer customerId;

//    对一的关系,所以要保留customer的对象
    Customer customer ;
}
package com.atgui.pojo;

import lombok.Data;

@Data
public class Customer {

    private Integer customerId;

    private String  customerName;

}

3、准备配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    让mybatis开启日志输出-->
    <settings>
<!--        这里设置的是选择用system进行日志输出-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        开启驼峰式自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

<!--    定义自己类的别名-->
    <typeAliases>
<!--        单独定义-->
<!--        <typeAlias type="com.atgui.pojo.Employee" alias="suibian"/>-->
<!--        批量定义-->
        <package name="com.atgui.pojo"/>
    </typeAliases>

    <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
    <environments default="development">
        <!-- environment表示配置Mybatis的一个具体的环境 -->
        <environment id="development">
            <!-- Mybatis的内置的事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
        <!-- mapper标签:配置一个具体的Mapper映射文件 -->
        <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
        <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
        <mapper resource="mappers/OrderMapper.xml"/>
    </mappers>

</configuration>

4、pom.xml和上面一样这里不多赘述

5、准备接口类

package com.atgui.mapper;

import com.atgui.pojo.Order;

public interface OrderMapper {
  Order selectOrderWithCustomer(Integer orderId);
}

6、准备mappers/mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.atgui.mapper.OrderMapper">

    <resultMap id="orderMap" type="order">
<!--        第一层属性,order对象-->
        <id column="order_id" property="orderId"/>
        <result column="order_name" property="orderName"/>
        <result column="customer_id" property="customerId"/>

<!--        第二层属性,customer对象-->
        <association property="customer" javaType="customer">
            <id column="customer_id" property="customerId"/>
            <result column="customer_name" property="customerName"/>
        </association>
    </resultMap>

    <select id="selectOrderWithCustomer" resultMap="orderMap">
        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>
</mapper>

7、测试

package com.atgui;

import com.atgui.mapper.UserMapper;
import com.atgui.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MybatisTest {

    private SqlSession sqlSession;

//    每次测试方法执行前都会执行该代码
    @BeforeEach
    public void before() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sqlSessionFactory.openSession(true);
    }

    //每次测试方法执行后都会执行该代码
    @AfterEach
    public void clean(){
        sqlSession.close();
    }
    @Test
    public void testInsert(){
        User user = new User();
        user.setUsername("1231");
        user.setPassword("123");
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.insert(user);
        System.out.println("userMapper = " + userMapper);
    }

    @Test
    public void testUpdate(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectById(1);//查询到这个再进行修改
        user.setUsername("12311111");
        user.setPassword("12322222");
        userMapper.update(user);
    }

    @Test
    public void testDelete(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.delete(1);
    }

    @Test
    public void testSelectById(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user =  userMapper.selectById(1);
        System.out.println("user = " + user);
    }

    @Test
    public void testSelectAll(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.selectAll();
        System.out.println("userList = " + userList);
    }
}

3、关键字

1、在“对一”关联关系中,我们的配置比较多,但是关键词就只有:associationjavaType

3、对多映射

1、需求

1、查询客户和客户订单关联的订单信息

2、代码实现

1、准备实体类

package com.atgui.pojo;

import lombok.Data;

import java.util.List;

@Data
public class Customer {

    private Integer customerId;

    private String  customerName;
    //对多的关系,就用一个集合装Order
    private List<Order> orderList;

}
package com.atgui.pojo;

import lombok.Data;

@Data
public class Order {

    private Integer orderId;

    private String orderName;

    private Integer customerId;

//    对一的关系,所以要保留customer的对象
    Customer customer ;
}

3、准备配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    让mybatis开启日志输出-->
    <settings>
<!--        这里设置的是选择用system进行日志输出-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        开启驼峰式自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

<!--    定义自己类的别名-->
    <typeAliases>
<!--        单独定义-->
<!--        <typeAlias type="com.atgui.pojo.Employee" alias="suibian"/>-->
<!--        批量定义-->
        <package name="com.atgui.pojo"/>
    </typeAliases>

    <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
    <environments default="development">
        <!-- environment表示配置Mybatis的一个具体的环境 -->
        <environment id="development">
            <!-- Mybatis的内置的事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
        <!-- mapper标签:配置一个具体的Mapper映射文件 -->
        <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
        <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
        <mapper resource="mappers/OrderMapper.xml"/>
        <mapper resource="mappers/CustomerMapper.xml"/>
    </mappers>

</configuration>

4、pom.xml和上面一样这里不多赘述

5、准备接口类

package com.atgui.mapper;

import com.atgui.pojo.Customer;

import java.util.List;

public interface CustomerMapper {

    List<Customer> queryList();

}

6、准备mappers/mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.atgui.mapper.CustomerMapper">

    <resultMap id="customerMap" type="customer">
        <id column="customer_id" property="customerId"/>
        <result column="customer_name" property="customerName"/>

<!--        是给集合属性赋值
            property 集合属性值
            ofType 集合的泛型类型
-->
        <collection property="orderList" ofType="order">
            <id column="order_id" property="orderId"/>
            <result column="order_name" property="orderName"/>
            <result column="customer" property="customerId"/>
        </collection>

    </resultMap>

    <select id="queryList" resultMap="customerMap">
        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

    </select>
</mapper>

7、测试

package com.atgui;

import com.atgui.mapper.CustomerMapper;
import com.atgui.mapper.OrderMapper;
import com.atgui.pojo.Customer;
import com.atgui.pojo.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class mybatisTest {
    private SqlSession sqlSession;

    //    每次测试方法执行前都会执行该代码
    @BeforeEach
    public void before() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sqlSessionFactory.openSession(true);
    }

    //每次测试方法执行后都会执行该代码
    @AfterEach
    public void clean(){
        sqlSession.close();
    }

    @Test
    public void  test2(){
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> customerList = customerMapper.queryList();
        System.out.println("order = " + customerList);

    }

}

3、理解和补充

1、对应关系如图

image-20240114232055922

4、关键字

1、在“对多”关联关系中,同样有很多配置,但是提炼出来最关键的就是:“collection”和“ofType”

4、多表映射总结

1、多表映射优化

1、补充setting设置

setting属性 属性含义 可选值 默认值
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 NONE, PARTIAL, FULL PARTIAL

2、根据上面的对多例子

  • ①修改mybatis-config.xml的配置文件

  • 
    
          
    
    
          
    
          
          
      
    
    

    ②修改CustomerMapper.xml文件

    
    
    
    
    
      
          
      
    
    
          
              
     
     
          
    
      
    
      
    

2、总结

关联关系 配置项关键词 所在配置文件和具体位置
对一 association标签/javaType属性/property属性 Mapper配置文件中的resultMap标签内
对多 collection标签/ofType属性/property属性 Mapper配置文件中的resultMap标签内

3、补充【多表】

image-20240115004830365

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇