本篇博客基于前面几篇博客的基础上继续深入学习的: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,一对一关联查询讲解到这。