年轻的时候,遇见了一个人,便以为余生再没有江湖,后来,才懂,她才是江湖的起源。

上一章简单介绍了MyBatis的动态Sql查询(七),如果没有看过,请观看上一章。

一. MyBatis的一对一映射

在业务开发中,常常会遇到关联联系的,如表与表之间的一对一关系。如,员工与员工的身份证号, 这就是典型的一对一。 可以与Hibernate的一对一 区别理解。 Hibernate的一对一映射地址为

员工表 User:

MyBatis的一对一映射(八)_java

身份证表 IdCard:

MyBatis的一对一映射(八)_sql_02

其中,IdCard 表中的 uid 并不是外键,只是User 表中id 相对应的那个字段, 值完全一样,但并不用外键,避免删除和修改时与User 表有太大的影响。

其所对应的实体类为:

User.java

package com.yjl.pojo;

/**
@author:yuejl
@date: 2019年6月15日 上午11:11:02
@Description Mybatis 使用的基本类 User
*/
public class User {
/**
* @param id id编号,自增
* @param name 姓名
* @param age 年龄
* @param sex 性别
* @param description 描述
*/
private Integer id;
private String name;
private Integer age;
private String sex;
private String description;

//引入id card 的关联类型.
private IdCard idCard;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", descriptinotallow=" + description
+ ", idCard=" + idCard + "]";
}
}

IdCard.java 类:

package com.yjl.pojo;
/**
@author: yuejl
@date: 2019年7月5日 下午12:41:47
@Description 类的相关描述
*/
public class IdCard {
/**
* @param uid 身份证唯一标识符
* @param idNum 身份证标识符
*/
private Integer id;
private String idNum;

//引入员工的属性
private User userId;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getIdNum() {
return idNum;
}
public void setIdNum(String idNum) {
this.idNum = idNum;
}
public User getUserId() {
return userId;
}
public void setUserId(User userId) {
this.userId = userId;
}
@Override
public String toString() {
return "IdCard [id=" + id + ", idNum=" + idNum + ", userId=" + userId + "]";
}
}

二. ResultMap 元素

resultMap 中所具有的元素有:

<resultMap>
<!--构造函数-->
<constructor>
<!--主键的-->
<idArg />
<!--普通属性-->
<arg/>
</constructor>
<!--属性主键-->
<id />
<!--普通属性 result-->
<result />
<!--一对一关联查询-->
<association />
<!---一对多关联查询-->
<collection />
<!--鉴别器-->
<discriminator javaType="">
<case value=""></case>
</discriminator>
</resultMap>

id,result 前面已经讲解过了, 下面讲解一下 constructor 和 association, collection和discriminator 后面章节会讲。

constructor 为构造参数, 在User 表中添加 构造方法, 参数为 id,普通属性有 name 和sex。 手动添加空构造方法。

public User(){

}
public User(Integer id,String name,String sex){
this.id=id;
this.name=name;
this.sex=sex;
}

接口为:

public User getById(int id);

则以前的id,result 为:

<resultMap type="user" id="userResultMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
</resultMap>
<!-- 嵌套结果 -->
<select id="getById" parameterType="int" resultMap="userResultMap">
select * from user where id=#{id}
</select>

则可以改成:

<resultMap type="user" id="userResultMap">
<constructor>
<!--顺序与构造方法的参数顺序必须一样。 javaType 必须填写。-->
<idArg javaType="int" column="id" />
<arg javaType="string" column="name"/>
<arg javaType="string" column="sex"/>
</constructor>
</resultMap>

其中, javaType 如果是Integer, 则可以写成’int’, 如果类型是 int,则可以写成’_int’ ,字符串 为’string’.
注意,不要用name 节点. 3.4.3版本之后,才添加了注解。

三. 一对一关联映射

一对一关联映射有两种方式,一种是嵌套结果的,一种是嵌套查询的,都是通过assocation 元素来完成的。 下面会重点介绍一下。

三.一 嵌套结果的一对一查询

嵌套结果,就是将关联的表,即user,idcard 表进行连接查询,将所有的查询结果放置在一个结果集里面,Mybatis 会将这个结果集进行分类组装成新的对象。

接口:

public User getByIdWithResult(@Param(value="id") int id);

sql 语句:

<resultMap type="user" id="userResultMapWithResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
<!--property 为属性, 注意,一定不要忘记写 javaType 来指明构造哪个实体类-->
<association property="idCard" javaType="idCard">
<!--内部为 连接类 IdCard 中的属性 和关联表IdCard 中的字段-->
<id property="id" column="id"/>
<result property="idNum" column="idnum"/>
</association>
</resultMap>
<select id="getByIdWithResult" parameterType="int" resultMap="userResultMapWithResult">
<!--关联的sql语句-->
select * from user u,idCard i where u.id=i.id and u.id=#{id}
</select>

测试方法:

@Test
public void findByIdWithResultTest(){
SqlSession sqlSessinotallow=SqlSessionFactoryUtils.getSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User user=userMapper.getByIdWithResult(1);
System.out.println(user);
}

测试运行,控制台打印:

MyBatis的一对一映射(八)_sql_03

会发现 IdCard 中的uid 没有值, 那是因为 在实体类 IdCard 中并没有 uid 这个属性。 在IdCard 中也应该添加一个private User user 即User 表的引用,来达到双向关联的目的。 既可以从员工查到IdCard, 也可以从IdCard 查找到对应的员工。 用法一样,故只用一个来举例。

三.二 嵌套查询 用select引入其他空间的查询语句

接口:

public User getByIdWithSelect(int id);

sql语句:

<resultMap type="user" id="userResultMapWithSelect">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>

<!--用了一个column,表示要传入的是哪一个参数的值, select 指明的是哪一个命名空间的哪一条语句-->
<association property="idCard" javaType="idCard"
column="id" select="com.yjl.mapper.IdCardMapper.findByUserId">
</association>
</resultMap>
<select id="getByIdWithSelect" parameterType="int" resultMap="userResultMapWithSelect">
<!--是单语句-->
select * from user u where u.id=#{id}
</select>

IdCardMapper.java 中有一个接口:

public IdCard findById(int id);

IdCardMapper.xml 的文件配置为:

<?xml versinotallow="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.yjl.mapper.IdCardMapper">
<resultMap type="idCard" id="idCardResultMap">
<id property="id" column="id"/>
<result property="idNum" column="idNum"/>
</resultMap>
<!-- 嵌套结果 -->
<select id="findById" parameterType="int" resultMap="idCardResultMap">
select * from idCard where id=#{id}
</select>

<!-- 嵌套查询的sql, 没有对应的接口,传入的参数为int 类型 -->
<select id="findByUserId" parameterType="int" resultMap="idCardResultMap">
select * from idCard where uid=#{id}
</select>
</mapper>

测试方法为:

@Test
public void findByIdWithSelectTest(){
SqlSession sqlSessinotallow=SqlSessionFactoryUtils.getSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User user=userMapper.getByIdWithSelect(1);
System.out.println(user);
}

MyBatis的一对一映射(八)_MyBatis的一对一映射_04

可以看出,进行了两条 sql语句的查询。

谢谢!!!