系列学习 SpringBoot 整合 Mybatis 之第 5 篇 —— <association> 标签实现一对一关联查询(级联查询)

本篇博客基于前面几篇博客的基础上继续深入学习的:https://blog.csdn.net/BiandanLoveyou/article/details/116528151

一对一级联关系在开发中经常遇到。比如一个用户对应一条个人信息。在 mybatis 中,通过 <resultMap> 元素的子元素 <association> 处理这种一对一级联关系。

在 <association> 元素中通常使用以下属性。
property:指定映射到实体类的对象属性。
column:指定表中对应的字段(即查询返回的列名,用该字段去关联查询)。
javaType:指定映射到实体对象属性的类型。
select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。

为了大家查阅信息方便,这里直接给出核心代码(有2种方式),如果有时间可以继续往后面看!


  <!-- 一对一关联查询方式1 -->
  <resultMap id="BaseResultMap_1" type="com.study.entity.StudentEntity">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="student_no" jdbcType="VARCHAR" property="studentNo" />
    <result column="student_name" jdbcType="VARCHAR" property="studentName" />
    <result column="introduce" jdbcType="VARCHAR" property="introduce" />

    <!-- 一对一关联查询 -->
    <association
      property="infoEntity"
      column="student_no"
      javaType="com.study.entity.InfoEntity"
      select="com.study.dao.InfoEntityMapper.getByNo"
    />

  </resultMap>

  <!-- 根据学号查询所有信息(主表信息和关联表信息) -->
  <select id="getAllInfoByNo_1" parameterType="java.lang.String" resultMap="BaseResultMap_1">
    select * from t_student
    where student_no = #{studentNo,jdbcType=VARCHAR}
  </select>




  <!-- 一对一关联查询方式2 -->
  <resultMap id="BaseResultMap_2" type="com.study.entity.StudentEntity">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="student_no" jdbcType="VARCHAR" property="studentNo" />
    <result column="student_name" jdbcType="VARCHAR" property="studentName" />
    <result column="introduce" jdbcType="VARCHAR" property="introduce" />

    <!-- 一对一关联查询 -->
    <association property="infoEntity" javaType="com.study.entity.InfoEntity">
      <id column="info_id" jdbcType="INTEGER" property="id" />
      <result column="info_student_no" jdbcType="VARCHAR" property="studentNo" />
      <result column="age" jdbcType="INTEGER" property="age" />
      <result column="sex" jdbcType="VARCHAR" property="sex" />
    </association>

  </resultMap>

  <!-- 根据学号查询所有信息(主表信息和关联表信息) -->
  <select id="getAllInfoByNo_2" parameterType="java.lang.String" resultMap="BaseResultMap_2">
    select s.*,f.id as info_id,f.student_no as info_student_no,f.age,f.sex
    from t_student as s
    left join t_info as f
    on s.student_no = f.student_no
    where s.student_no = #{studentNo,jdbcType=VARCHAR}
  </select>

 

详细内容如下

前面已经有了学生表:

CREATE TABLE `t_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_no` varchar(50) DEFAULT NULL COMMENT '学号',
  `student_name` varchar(50) DEFAULT NULL COMMENT '学生姓名',
  `introduce` varchar(255) DEFAULT NULL COMMENT '自我介绍',
  PRIMARY KEY (`id`),
  KEY `student_no` (`student_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

接下来我们再创建一个学生信息表,并制造一些测试数据:

CREATE TABLE `t_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_no` varchar(50) DEFAULT NULL COMMENT '学号,对应 t_student 的 student_no 字段',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `sex` varchar(10) DEFAULT NULL COMMENT '性别',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我们先创建学生信息的实体类:

package com.study.entity;

/**
 * @author biandan
 * @description 学生信息实体类
 * @signature 让天下没有难写的代码
 * @create 2021-05-11 下午 10:44
 */
public class InfoEntity {

    private Integer id;

    private String studentNo;//学号

    private Integer age;//年龄

    private String sex;//性别

    @Override
    public String toString() {
        return "InfoEntity{" +
                "id=" + id +
                ", studentNo='" + studentNo + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getStudentNo() {
        return studentNo;
    }
    public void setStudentNo(String studentNo) {
        this.studentNo = studentNo;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

然后,在 resources 目录下创建 InfoEntityMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.dao.InfoEntityMapper">

  <resultMap id="BaseResultMap" type="com.study.entity.InfoEntity">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="student_no" jdbcType="VARCHAR" property="studentNo" />
    <result column="age" jdbcType="INTEGER" property="age" />
    <result column="sex" jdbcType="VARCHAR" property="sex" />
  </resultMap>

  <!-- 根据学号查询信息 -->
  <select id="getByNo" parameterType="java.lang.String" resultMap="BaseResultMap">
    select * from t_info
    where student_no = #{studentNo,jdbcType=VARCHAR}
  </select>

</mapper>

在 dao 层创建接口:InfoEntityMapper

package com.study.dao;

import com.study.entity.InfoEntity;
import com.study.entity.StudentEntity;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
import java.util.Map;

@Mapper //如果不在 dao 层增加 @Mapper 注解,就在启动类增加扫描 dao 层的包
public interface InfoEntityMapper {


    /**
     * 根据学号查询
     * @param studentNo
     * @return
     */
    InfoEntity getByNo(String studentNo);

}

 

然后在学生的主体类上,加上信息的实体类对象:

package com.study.entity;

public class StudentEntity {
    //主键ID
    private Integer id;

    //学号
    private String studentNo;

    //姓名
    private String studentName;

    //自我介绍
    private String introduce;

    //学生信息实体类
    private InfoEntity infoEntity;

    @Override
    public String toString() {
        return "StudentEntity{" +
                "id=" + id +
                ", studentNo='" + studentNo + '\'' +
                ", studentName='" + studentName + '\'' +
                ", introduce='" + introduce + '\'' +
                ", infoEntity=" + infoEntity +
                '}';
    }

    public InfoEntity getInfoEntity() {
        return infoEntity;
    }
    public void setInfoEntity(InfoEntity infoEntity) {
        this.infoEntity = infoEntity;
    }
    public Integer getId() {return id;}
    public void setId(Integer id) {
        this.id = id;
    }
    public String getStudentNo() {
        return studentNo;
    }
    public void setStudentNo(String studentNo) {
        this.studentNo = studentNo;
    }
    public String getStudentName() {
        return studentName;
    }
    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }
    public String getIntroduce() {
        return introduce;
    }
    public void setIntroduce(String introduce) {
        this.introduce = introduce;
    }
}

然后我们修改 mybatis 的配置,启用延迟加载。即修改 resources 目录下的文件:mybatis-config.xml。在使用 MyBatis 嵌套查询方式进行关联查询时,使用 MyBatis 的延迟加载可以在一定程度上提高查询效率。

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

    <!-- 全局配置参数 -->
    <settings>
        <!-- 使全局的映射器启用或禁用缓存。 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- debug 模式打印 sql 语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>

        <!--在使用MyBatis嵌套查询方式进行关联查询时,使用MyBatis的延迟加载可以在一定程度上提高查询效率-->
        <!--打开延迟加载的开关-->
        <setting name= "lazyLoadingEnabled" value= "true"/>
        <!--将积极加载改为按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

</configuration>

 

然后,我们编写 Mybatis 的 xml 文件:StudentEntityMapper.xml (注意,这里只列出关键的代码,其它代码不罗列)(核心代码


  <!-- 一对一关联查询方式1 -->
  <resultMap id="BaseResultMap_1" type="com.study.entity.StudentEntity">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="student_no" jdbcType="VARCHAR" property="studentNo" />
    <result column="student_name" jdbcType="VARCHAR" property="studentName" />
    <result column="introduce" jdbcType="VARCHAR" property="introduce" />

    <!-- 一对一关联查询 -->
    <association
      property="infoEntity"
      column="student_no"
      javaType="com.study.entity.InfoEntity"
      select="com.study.dao.InfoEntityMapper.getByNo"
    />

  </resultMap>

  <!-- 根据学号查询所有信息(主表信息和关联表信息) -->
  <select id="getAllInfoByNo_1" parameterType="java.lang.String" resultMap="BaseResultMap_1">
    select * from t_student
    where student_no = #{studentNo,jdbcType=VARCHAR}
  </select>




  <!-- 一对一关联查询方式2 -->
  <resultMap id="BaseResultMap_2" type="com.study.entity.StudentEntity">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="student_no" jdbcType="VARCHAR" property="studentNo" />
    <result column="student_name" jdbcType="VARCHAR" property="studentName" />
    <result column="introduce" jdbcType="VARCHAR" property="introduce" />

    <!-- 一对一关联查询 -->
    <association property="infoEntity" javaType="com.study.entity.InfoEntity">
      <id column="info_id" jdbcType="INTEGER" property="id" />
      <result column="info_student_no" jdbcType="VARCHAR" property="studentNo" />
      <result column="age" jdbcType="INTEGER" property="age" />
      <result column="sex" jdbcType="VARCHAR" property="sex" />
    </association>

  </resultMap>

  <!-- 根据学号查询所有信息(主表信息和关联表信息) -->
  <select id="getAllInfoByNo_2" parameterType="java.lang.String" resultMap="BaseResultMap_2">
    select s.*,f.id as info_id,f.student_no as info_student_no,f.age,f.sex
    from t_student as s
    left join t_info as f
    on s.student_no = f.student_no
    where s.student_no = #{studentNo,jdbcType=VARCHAR}
  </select>

再次解读 <association> 元素中通常使用以下属性。
property:指定映射到实体类的对象属性。这里的 infoEntity 对应的是 StudentEntity 里 InfoEntity 的对象,一个字母都不能差,要一模一样!

javaType:指定映射到实体对象属性的类型。这里映射到 InfoENtity 的全限路经。

在方式1中,我们使用以下两个属性:
column:指定表中对应的字段(即查询返回的列名,用该字段去关联查询)。这里使用学号 studenNo 去关联查询。
select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。这里直接调用 dao 层的 getByNo 方法获取查询结果。

在方式2中,我们直接把 InfoEntity 的属性罗列出来,需要注意的是,我们需要给 InfoEntity 的 id 、studen_no 起别名,否则会和 StudentEntity 的 id 、studen_no 冲突导致数据错乱!

 

然后,编写 dao 层的接口:

    StudentEntity getAllInfoByNo_1(String studentNo);


    StudentEntity getAllInfoByNo_2(String studentNo);

然后在业务层调用 dao 层接口,关键代码如下:

        //根据学号查询所有信息(主表信息和关联表信息)
        String studentNo = "12310";

        StudentEntity entity = studentEntityMapper.getAllInfoByNo_1(studentNo);
        System.out.println(entity.toString());
        System.out.println("********************************");

        //根据学号查询所有信息(主表信息和关联表信息)
        StudentEntity entity_2 = studentEntityMapper.getAllInfoByNo_2(studentNo);
        System.out.println(entity_2.toString());

启动测试,控制台输出:

方式 1 执行了2条SQL语句。方式 2 使用左关联查询,只执行了一条SQL语句。

==>  Preparing: select * from t_student where student_no = ? 
==> Parameters: 12310(String)
<==    Columns: id, student_no, student_name, introduce
<==        Row: 1, 12310, 张三, 你好啊
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2cae3a58]
JDBC Connection [com.mysql.jdbc.JDBC4Connection@6395a6fd] will not be managed by Spring
==>  Preparing: select * from t_info where student_no = ? 
==> Parameters: 12310(String)
<==    Columns: id, student_no, age, sex
<==        Row: 1, 12310, 18, 男
<==      Total: 1
StudentEntity{id=1, studentNo='12310', studentName='张三', introduce='你好啊', infoEntity=InfoEntity{id=1, studentNo='12310', age=18, sex='男'}}

*************************************************************

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@30a97670] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.jdbc.JDBC4Connection@6395a6fd] will not be managed by Spring
==>  Preparing: select s.*,f.id as info_id,f.student_no as info_student_no,f.age,f.sex from t_student as s left join t_info as f on s.student_no = f.student_no where s.student_no = ? 
==> Parameters: 12310(String)
<==    Columns: id, student_no, student_name, introduce, info_id, info_student_no, age, sex
<==        Row: 1, 12310, 张三, 你好啊, 1, 12310, 18, 男
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@30a97670]
StudentEntity{id=1, studentNo='12310', studentName='张三', introduce='你好啊', infoEntity=InfoEntity{id=1, studentNo='12310', age=18, sex='男'}}

 

OK,一对一关联查询讲解到这。

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值