MyBatis-多表查询

MyBatis-多表查询

  • 多表查询的sql语句仍然需要我们自己编写(连接查询)

  • 自己设计存储数据的实体类,承接多个表的查询结果

  • 使用自定义结果集映射(resultMap)


多表之间的关系

在数据库中,多表之间存在多个关系:

  • 一对一
  • 一对多
  • 多对多

但在实体类中,多实体类中只看单向的关系,比如:

一个客户对应多个订单,就是对多的关系

一个订单对应多个客户,就是对一的关系

在微头条项目中,我们学会了值对象(VO),使用这种对象可以接受数据库多表查询的结果

而现在,我们解决多表查询的方法是,将一个实体类对象作为属性放到另一个实体类中

如果为对一关系,比如上面的例子,就在订单实体类中存放一个客户实体类对象作为属性

如果为对多关系,比如上面的例子,就在客户实体类中存放一个类型为客户实体类的List集合作为属性

在实际开发中,只有在查询所需时才修改实体类,并且修改时只做一个实体类的修改,其对应的不需要考虑


对一映射

pojo
@Data
public class Customer {
    private int customerId;
    private String customerName;
}
@Data
public class Order {
    private Integer orderId;
    private String orderName;
    private int customerId;
    private Customer customer;
}
mapper接口
public interface OrderMapper {
    Order queryOrderById(Integer id);
}
mapper.xml

使用resultMap标签为查询结果做映射

通过association,即可为对象中的对象属性做映射,在标签中套用子标签即可赋值对象属性的属性

  • property属性:属性名
  • javaType:类的全限定符或类别名
<?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">

<mapper namespace="com.xiaobai.mapper.OrderMapper">
    <resultMap id="orderMap" type="order">
        <id column="order_id" property="orderId"/>
        <result column="order_name" property="orderName"/>
        <result column="customer_id" property="customerId"/>
        <!--给对象赋值-->
        <association property="customer" javaType="customer">
            <id column="customer_id" property="customerId"/>
            <result column="customer_name" property="customerName"/>
        </association>
    </resultMap>

    <select id="queryIdby" resultMap="orderMap">
        select * from t_order tor join t_customer tur
        on tor.customer_id = tur.customer_id
        where tor.order_id = #{id}
    </select>
</mapper>

对多映射

pojo
public class Customer {
    private int customerId;
    private String customerName;

    private List<Order> orders;
}
public class Order {
    private Integer orderId;
    private String orderName;
    private int customerId;
    private Customer customer;
}
mapper接口
public interface CustomerMapper {
    List<Customer> selectAllCustomer();
}
mapper.xml

使用resultMap标签为查询结果做映射

通过collection,即可为对象中的List集合属性做映射,在标签中套用子标签即可赋值集合中对象属性的属性

  • property属性:属性名
  • ofType:集合的泛型,也就是集合中的对象的数据类型

注:我们在进行两个表的相互映射过程中,只考虑单向的映射关系,比如在这个例子中,我们在List集合中的order对象中也存在customer对象,但不要映射此对象,否则会出现映射循环

<?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">

<mapper namespace="com.xiaobai.mapper.CustomerMapper">
    <resultMap id="customerMapper" type="customer">
        <id column="customer_id" property="customerId"/>
        <result column="customer_name" property="customerName"/>
        <!--映射集合对象-->
        <collection property="orders" ofType="order">
            <id column="order_id" property="orderId"/>
            <result column="order_name" property="orderName"/>
            <result column="customer_id" property="customerId"/>
        </collection>
    </resultMap>

    <select id="selectAllCustomer" resultMap="customerMapper">
        select *
        from t_order tor join t_customer tur
        on tor.customer_id = tur.customer_id
    </select>

</mapper>

autoMapppingBehavior

配置mybatis-config.xml的setting标签,开启此功能,指定 MyBatis 应如何自动映射列到字段或属性

注:仅仅映射result也就是常规列的内容,主键列不会自动映射

value属性有三个选项值:

  • NONE:关闭自动映射
  • PARTIAL:部分映射
  • FULL:深度映射

默认情况下,resultMap只会映射一层result的标签,也就是说,不支持对一和对多映射对象属性(集合属性)

<settings>
    <!-- 开启MyBaits日志输出 -->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!-- 开启MyBaits驼峰式映射 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!--开启MyBatis自动映射列到字段或属性(单一层次)-->
    <setting name="autoMappingBehavior" value="PARTIAL"/>
</settings>

value值更改为FULL,则开启深层次映射

<settings>
    <!-- 开启MyBaits日志输出 -->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!-- 开启MyBaits驼峰式映射 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!--开启MyBatis自动映射列到字段或属性(单一层次)-->
    <setting name="autoMappingBehavior" value="FULL"/>
</settings>
    <resultMap id="customerMapper" type="customer">
        <id column="customer_id" property="customerId"/>
<!--        <result column="customer_name" property="customerName"/>-->
        <!--映射集合对象-->
        <collection property="orders" ofType="order">
            <id column="order_id" property="orderId"/>
<!--            <result column="order_name" property="orderName"/>-->
<!--            <result column="customer_id" property="customerId"/>-->
        </collection>
    </resultMap>

在进行深层次映射时,我不禁想到一个问题,深层次映射是否会导致映射循环

但仔细阅读代码发现,深层次映射也只是根据collection和association标签来进行映射

在resultMap中,当发现对象属性(集合属性)则不进行自动映射,进而寻找collection(association)标签

一个标签代表着一个对象(一个集合),这样就完美的避免了映射循环的问题