day07-MyBatis的关联映射01
MyBatis的关联映射
实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系。
1.关联关系概述
在关系型数据库中,多表之间存在着三种关系,分别是一对一,一对多,多对多。
一对一:在任意一个表中引入另外一个表的主键作为外键。
一对多:在多个表中都引入了某一个表的主键作为外键
多对多:需要用一张中间表表示多对多的关系,这张中间表引入两张表的主键作为外键。
一般来说一个对象映射一张表,因此一对一的关系就是在A类中定义B类属性,一对多的关系就是在A类中定义List< B> 的属性,多对多就是分别在A、B类中定义对方的List 属性。
2.一对一
一对一关系是一个基本的映射关系,比如Person(人)--IDCard(身份证),我们可以通过如下两种方式实现:
- 通过配置XxxMapper.xml实现1对1 [配置方式]
- 通过注解的方式实现1对1 [注解方式]
2.1配置方式
2.1.1环境搭建
配置映射文件来实现一对一的映射关系,实现级联查询,要求通过person可以获取到对应的idencard信息
关于级联查询:若表A中有一个外键引用了表B的主键,A表就是子表,B表就是父表。当查询表A的数据时,通过表A的外键将表B的记录也查找出来,这就是级联查询。相应的还有级联删除,当删除B表的记录时,会先将A表中关联的记录删掉
(1)person表和 idencard表
-- 创建 idencard 表
-- 记录身份证
CREATE TABLE `idencard`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`card_sn` VARCHAR(32) NOT NULL DEFAULT ''
)CHARSET utf8;
INSERT INTO `idencard` VALUES(1,'123456789098765');
-- 创建person表
CREATE TABLE `person`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL DEFAULT '',
`card_id` INT, -- 对应idencard表的主键-id
FOREIGN KEY (`card_id`) REFERENCES idencard (`id`)-- card_id作为外键
)CHARSET utf8;
INSERT INTO `person` VALUES(1,'张三',1);
(2)实体类 IdenCard 和 Person
package com.li.entity;
/**
* @author 李
* @version 1.0
*/
public class IdenCard {
private Integer id;
private String card_sn;
//省略setter,getter,toString方法
}
package com.li.entity;
/**
* @author 李
* @version 1.0
*/
public class Person {
private Integer id;
private String name;
private IdenCard card;
//省略setter,getter,toString方法
}
(3)PersonMapper 接口
package com.li.mapper;
import com.li.entity.Person;
/**
* @author 李
* @version 1.0
*/
public interface PersonMapper {
//通过Person的id获取到Person,包括这个Person关联的IdenCard对象(级联操作)
public Person getPersonById(Integer id);
}
2.1.2方式1:多表联查
PersonMapper.xml映射文件实现级联查询,实现方法是使用多表联查,返回的数据通过resultMap结果映射
<mapper namespace="com.li.mapper.PersonMapper">
<!--1.接口声明:public Person getPersonById(Integer id);
2.通过Person的id获取到Person,包括这个Person关联的IdenCard对象(级联操作)
3.返回类型如果配置成resultType="Person",不能实现级联查询,
在返回的person对象中IdenCard属性对象为 null
4.因此需要使用自定义resultMap,在resultMap中指定级联关系-->
<select id="getPersonById" parameterType="Integer" resultMap="PersonResultMap">
SELECT * FROM `person`,`idencard` WHERE `person`.`id`= #{id} AND
`person`.`card_id` = `idencard`.`id`;
</select>
<!--association – 一个复杂类型的关联;许多结果将包装成这种类型嵌套结果映射 – 关联可以是
resultMap 元素,或是对其它结果映射的引用
1.property="card" 表示 Person对象的card属性
2.javaType="IdenCard" 表示card属性的类型-->
<resultMap id="PersonResultMap" type="Person">
<!--id标签–一个ID结果(就是主键);标记出作为主键的结果可以帮助提高整体性能-->
<!--这里的property表示Person类的属性名,column表示对应表的字段-->
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="card" javaType="IdenCard">
<!--这里的property表示IdenCard类的属性名,column表示表的字段名-->
<result property="id" column="id"/>
<result property="card_sn" column="card_sn"/>
</association>
</resultMap>
</mapper>
测试:
@Test
public void getPersonById() {
Person person = personMapper.getPersonById(1);
System.out.println("person=" + person);
if (sqlSession != null) {
sqlSession.close();
}
}
2.2.3方式2:分解为多次单表操作(推荐使用)
第一种方式使用了多表联查的形式实现级联查询,但是如果涉及的表过多,sql语句可读性就会变差。第二种方式的核心思想是将多表联查分解成单表操作,这样更简洁,易于维护,而且可以复用你写好的方法,推荐使用
(1)创建IdenCardMapper接口
public interface IdenCardMapper {
//根据id获取到身份证序列号
public IdenCard getIdenCardById(Integer id);
}
(2)在IdenCardMapper的映射文件中实现该方法
<mapper namespace="com.li.mapper.IdenCardMapper">
<!--配置实现public IdenCard getIdenCardById(Integer id);-->
<select id="getIdenCardById" parameterType="Integer" resultType="IdenCard">
SELECT * FROM `idencard` WHERE `id` = #{id}
</select>
</mapper>
(3)PersonMapper接口
//通过Person的id获取到Person,包括这个Person关联的IdenCard对象(方式2)
public Person getPersonById2(Integer id);
(4)实现PersonMapper接口的映射文件
1. 先通过 SELECT * FROM person WHERE id =#{id} 返回 person 信息
2. 以第一个操作返回的 card_id 字段数据,作为条件再次查询,得到对应的 IdenCard 数据
如果第一个操作使用了别名,那么返回的时候的字段也是别名,因此第二个操作也要使用别名才能匹配到
<!--通过Person的id获取到Person,包括这个Person关联的IdenCard对象(方式2)
接口方法:public Person getPersonById2(Integer id);-->
<resultMap id="PersonResultMap2" type="Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!--第二种方式的核心思想是将多表联查操作分解成单表操作,
这样更简洁,易于维护,复用性更强,推荐使用-->
<!--1.property="card"表示Person对象的card属性
2.column="card_id"是SELECT * FROM person WHERE id = #{id}语句返回的card_id字段名/别名
3.返回的字段card_id信息/数据会作为getIdenCardById()的入参来执行方法-->
<association property="card" column="card_id"
select="com.li.mapper.IdenCardMapper.getIdenCardById"/>
</resultMap>
<select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2">
SELECT * FROM person WHERE id = #{id};
</select>
测试结果:
可以看到底层执行了两次sql查询操作。首先对person表进行查询,查询结果(card_id)作为第二张表的查询条件(id),再对idencard表进行查询。
2.2注解方式
通过注解的方式来实现一对一的映射关系,实现级联查询,通过person可以获取到对应的idencard的信息。这里只进行方式二的演示。
在实际开发中还是推荐使用配置方式
(1)注解实现方法
IdenCardMapperAnnotation 接口:
package com.li.mapper;
import com.li.entity.IdenCard;
import org.apache.ibatis.annotations.Select;
/**
* @author 李
* @version 1.0
* 使用注解的方式实现一对一的映射
*/
public interface IdenCardMapperAnnotation {
//根据id获取到身份证序列号
@Select(value = "SELECT * FROM `idencard` WHERE `id` = #{id}")
public IdenCard getIdenCardById(Integer id);
}
PersonMapperAnnotation 接口:
package com.li.mapper;
import com.li.entity.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
/**
* @author 李
* @version 1.0
*/
public interface PersonMapperAnnotation {
//通过Person的id获取到Person,包括这个Person关联的IdenCard对象
//注解的形式就是对前面xml配置方式的体现
@Select(value = "SELECT * FROM person WHERE id = #{id}")//如果这里返回的字段使用了别名,则@result的card_id也要使用该别名
@Results({//配置返回数据的映射
@Result(id = true, property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "card", column = "card_id",
one = @One(select = "com.li.mapper.IdenCardMapper.getIdenCardById"))
})
public Person getPersonById(Integer id);
}
(2)测试
@Test
public void getIdenCardById() {
Person person = personMapperAnnotation.getPersonById(1);
System.out.println("person=" + person);
if (sqlSession != null) {
sqlSession.close();
}
}
2.3注意事项
一张表是否设置了外键,对MyBatis进行对象级联映射没有影响,外键只是对表本身数据的约束
2.4练习
前面我们讲解的是查询Person可以级联查询到IdenCard,如果要求通过查询IdenCard,也可以级联查询到Person,应该如何解决?
day07-MyBatis的关联映射01的更多相关文章
- 04—mybatis的关联映射
mybatis的关联映射一对一一对多多对多 一.一对一(一个人只能有一个身份证号) 1.创建表创建表tb_card CREATE TABLE `tb_card` ( `id` int(11) NOT ...
- mybatis 一对一关联映射实例
在实际项目开发中,经常存在一对一的关系,如一个人对应一张身份证信息,这就是一对一的关系.下面是一个简单的实例: 1.建表过程我就省略了,主要是一张Person表,一张IDCard表,其相关属性见步骤2 ...
- mybatis之关联映射
###mybatis使用之一对一关联映射 1)分析并画ER图.(特别是一对一.一对多.多对多的情况) 2)启动终端数据库,并建库建表,在表中插入值和字段,并查看结果.(后期把navicat用上) 3) ...
- Mybatis的关联映射案例
主要是对之前学习的关联映射做一个案例,自己动手实践一下,可以理解的更好一点. 开发环境 开发工具:idea Java环境: jdk1.8.0_121 数据库:SQLServer 项目结构,里面包含了三 ...
- Mybatis的关联映射
实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系.针对多表之间的操作,MyBatis提供了关联映射, 通过关联映射就可以很好的处理对象与对象之间的关联关 ...
- MyBatis的关联映射和动态SQL
CREATE TABLE tb_card ( id INT PRIMARY KEY AUTO_INCREMENT, CODE ) ); '); CREATE TABLE tb_person ( id ...
- 【Hibernate框架】关联映射(一对一关联映射)
一.整理思路: 之前,小编总结过Mybatis的关联映射,接下来,再来总结一下hibernate的相关的关联映射,直接上图: 这张图,就是小编整理总结整个Hibernate的关联映射的一个大致思路. ...
- Mybatis(四)关联映射
一. Mybatis关联映射 1 讲数据库中关联关系,主键表与外键表 一对多,多对一,主键表表示一 与外键表表示多 学生与学校的关系,工人与工厂,人员与部门的关系,.... 多 一 ...
- SSM框架开发web项目系列(三) MyBatis之resultMap及关联映射
前言 在上篇MyBatis基础篇中我们独立使用MyBatis构建了一个简单的数据库访问程序,可以实现单表的基本增删改查等操作,通过该实例我们可以初步了解MyBatis操作数据库需要的一些组成部分(配置 ...
- MyBatis学习(七)MyBatis关联映射之多对多映射
对于数据库中的多对多关系建议使用一个中间表来维护关系. 1.创建四张表,分别为用户表,商品表,订单表,中间表. DROP TABLE IF EXISTS `t_user`; CREATE TABLE ...
随机推荐
- java (String)强制转换与toString()方法
1. Object.toString()介绍 Object中是自带有toString()方法的,也就是说java中的所有类的对象都是可以转换为字符串的. 首先,先看看Object.toString() ...
- Effective C++试读笔记
Part1 习惯C++ 1. 视C++为一个语言联邦 C++非常的屌,除了开发效率和编译效率不高,其他的都非常屌 C++ 可以视为一系列的语言联邦构成的紧密结合体,分为以下四个部分 C 2.C wit ...
- 启动springboot项目报错Unable to start embedded Tomcat
1.问题描述 最近在学习springcloud的时候,在父工程下新建一个model后,引入dashboard相关依赖后启动报错 2.产生原因 产生原因有可能就是pom.xml中下载的jar包版本冲突 ...
- [能源化工] TE田纳西-伊斯曼过程数据集
TE田纳西-伊斯曼过程数据集简介 TE数据集是现在故障诊断中的应用较多的一种数据集.主要介绍论文上都有. 具体介绍见:http://depts.washington.edu/control/LARRY ...
- [R语言] WGCNA入门教程
文章目录 wgcna入门-雌性小鼠肝脏表达数据的网络分析:寻找与体重有关的模块 1 数据输入和清洗 1.1 加载基因表达数据 1.2 数据清洗 1.3 加载临床特征数据 2 建设表达网络与模块检测 2 ...
- python进阶之路13 二分法 三元表达式 各种生成式 匿名函数
算法简介及二分法 1.什么是算法 算法就是解决问题的有效方法 不是所有的算法都很高效也有不合格的算法 2.算法应用场景 推荐算法(抖音视频推送 淘宝商品推送) 成像算法(AI相关)...... 几乎涵 ...
- Educational Codeforces Round 33 (Rated for Div. 2) 虚拟赛体验
前言 就只做出了 \(A,B,C,D\) 是不是很弱? A.Chess For Three A,B,C 三人下棋,A和B先下,每次下完棋之后由现在观战的人(例如第一局就由C)代替下输的人. 每次输入一 ...
- 03-Verilog语法
Verilog语法 1 Register 组合逻辑-->寄存器-->组合逻辑-->寄存器 Register是一个变量,用于存储值,并不代表一个真正的硬件DFF. reg A,C; / ...
- 使用Zolom内存解析运行python脚本(不落地)
在目标机器运行python工具 好多工具都是python写的,如果目标机器是linux的话自带python环境可以很方便的运行这些工具,但是windows下是不自带python环境的,所以一种办法是直 ...
- 【随笔记】Tina 系统的 ADB、声卡、网卡、串口多路共存
全志 Tina 系统的 USB Gadget 配置方法,随笔记录,实测为 R311 平台,其它平台应该通用. 一.配置内核 二.编译驱动并加载 # UAC insmod usb_f_uac1.ko ...