mybatis标签之——关联映射
关联关系是面向对象分析、面向对象设计最重要的知识。合理的关联映射将大大简化持久层数据的访问。关联关系大致分为以下三类:
- 一对一
- 一对多
- 多对多
1. 一对一
一对一关系推荐使用唯一主外键关联,即两张表使用外键关联关系,由于是一对一关联,因此还需要给外键列增加unique唯一约束。
-- 身份证表
create table tb_card {
id int primary key auto_increment,
code varchar(18)
};
insert into tb_card (code) values('');
-- 个人表
create table tb_person {
id int primary key auto_increment,
name varchar(18),
sex varchar(18),
age int,
card_id int unique, --card_id 唯一约束,且作为外键
foreign key (card_id) references tb_card (id)
};
insert into tb_person (name,sex,age,card_id) values('jack','男',23,1);
代码中创建Card对象和Person的对象(此处省略get/set方法)
public class Card implements Serializable { private Integer id; // 主键id
private String code; // 身份证编号
···
}
public class Person implements Serializable { private Integer id; // 主键id
private String name; // 姓名
private String sex; // 性别
private Integer age; // 年龄 // 人和身份证是一对一的关系,即一个人只有一个身份证,在Person类中定义card属性,来映射一对一关系
private Card card;
···
}
映射xml文件如下
CardMapper.xml
<!-- namespace指用户自定义的命名空间。 -->
<mapper namespace="org.zang.mapper.CardMapper">
<!-- 根据id查询Card,返回Card对象 -->
<select id="selectCardById" parameterType="int" resultType="org.zang.domain.Card">
SELECT * from tb_card where id = #{id}
</select>
</mapper>
PersonMapper.xml
<mapper namespace="org.zang.mapper.PersonMapper">
<!-- 映射Peson对象的resultMap -->
<resultMap type="org.zang.domain.Person" id="personMapper">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/> <!-- 一对一关联映射:association -->
<association property="card" column="card_id"
select="org.zang.mapper.CardMapper.selectCardById"
javaType="org.zang.domain.Card"/>
</resultMap> <!-- 根据id查询Person,返回resultMap -->
<select id="selectPersonById" parameterType="int"
resultMap="personMapper">
SELECT * from tb_person where id = #{id}
</select>
</mapper>
可以看到,personMapper中使用<association.../>元素来映射一对一的关联关系。
2. 一对多
数据库中一对多关系通常使用主外键关联,外键列应该在多方,即多方维护关系。
-- 班级表 (一)
create table tb_clazz(
id int primary key auto_increment,
code varchar(18),
name varchar(18)
);
insert into tb_clazz(code,name) values('j1601','java就业班'); -- 学生表 (多)
create table tb_student(
id int primary key auto_increment,
name varchar(18),
sex varchar(18),
age int,
clazz_id int, --clazz_id 作为外键参照tb_clazz的主键id
foreign key (clazz_id) references tb_clazz(id)
);
insert into tb_student(name,sex,age,clazz_id) values('jack','男',23,1);
insert into tb_student(name,sex,age,clazz_id) values('rose','女',18,1);
insert into tb_student(name,sex,age,clazz_id) values('tom','男',21,1);
insert into tb_student(name,sex,age,clazz_id) values('alice','女',20,1);
代码中创建Clazz对象和Student的对象(此处省略get/set方法)
public class Clazz implements Serializable { private Integer id; // 班级id,主键
private String code; // 班级编号
private String name; // 班级名称 // 班级和学生是一对多的关系,即一个班级可以有多个学生
private List<Student> students;
···
}
public class Student implements Serializable { private Integer id; // 学生id,主键
private String name; // 姓名
private String sex; // 性别
private Integer age; // 年龄 // 学生和班级是多对一的关系,即一个学生只属于一个班级
private Clazz clazz;
···
}
映射文件如下
ClazzMapper.xml
<mapper namespace="org.zang.mapper.ClazzMapper"> <!-- 映射Clazz对象的resultMap -->
<resultMap type="org.zang.domain.Clazz" id="clazzResultMap">
<id property="id" column="id"/>
<result property="code" column="code"/>
<result property="name" column="name"/> <!-- 一对多关联映射:collection fetchType="lazy"表示懒加载 -->
<collection property="students" javaType="ArrayList" column="id" ofType="org.zang.domain.Student"
select="org.zang.mapper.StudentMapper.selectStudentByClazzId" fetchType="lazy">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
</collection>
</resultMap> <!-- 根据id查询班级信息,返回resultMap -->
<select id="selectClazzById" parameterType="int" resultMap="clazzResultMap">
SELECT * FROM tb_clazz WHERE id = #{id}
</select> </mapper>
由于student属性是一个List集合,所有clazzResultMap中使用了<collection.../>元素映射一对多的关联关系。
此外还通过 fetchType="lazy" 来设置懒加载。fatch机制更多的是为了性能考虑,如果查询班级时确认会访问班级的所有学生,则该属性应该设置为eager;否则应该设置为lazy;正常情况下,一对多所关联的集合对象,都应该被设置成lazy。
使用懒加载还应该在mybatis-config.xml中增加如下配置
<settings>
<!-- 要使延迟加载生效必须配置下面两个属性 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
StudentMapper.xml
<mapper namespace="org.zang.mapper.StudentMapper"> <!-- 映射Student对象的resultMap -->
<resultMap type="org.zang.domain.Student" id="studentResultMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<!-- 多对一关联映射:association -->
<association property="clazz" javaType="org.zang.domain.Clazz">
<id property="id" column="id"/>
<result property="code" column="code"/>
<result property="name" column="name"/>
</association>
</resultMap> <!-- 根据id查询学生信息,多表连接,返回resultMap -->
<select id="selectStudentById" parameterType="int" resultMap="studentResultMap">
SELECT * FROM tb_clazz c,tb_student s
WHERE c.id = s.clazz_id
AND s.id = #{id}
</select> <!-- 根据班级id查询学生信息,返回resultMap -->
<select id="selectStudentByClazzId" parameterType="int"
resultMap="studentResultMap">
SELECT * FROM tb_student WHERE clazz_id = #{id}
</select> </mapper>
studentResultMap中使用<association.../>元素映射多对一的关联关系。因为<select id="selectStudentById".../>的sql语句是一条多表连接,关联tb_clazz表的同时查询了班级数据,所以<association.../>只是简单的装载数据。
tips:在实际开发中,由于一对多关系通常映射为集合对象,而由于多方的数据量可能很大,所以通常使用懒加载;而多对一只是关联到一个对象,所以通常使用多表连接直接提取出数据。
3. 多对多
在一个购物系统中,一个用户可以有多个订单,这是一对多的关系;一个订单中可以有多种商品,一种商品也可以属于多个不同的订单,订单和商品就是多对多的关系。
对于数据库中多对多的关系建议使用一个中间表来维护关系,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。
-- 用户表
create table tb_user(
id int primary key auto_increment,
username varchar(18),
loginname varchar(18),
password varchar(18),
phone varchar(18),
address varchar(18)
);
insert into tb_user(username,loginname,password,phone,address)
values('杰克','jack','','','广州'); -- 商品表
create table tb_article(
id int primary key auto_increment,
name varchar(18),
price double,
remark varchar(18)
); insert into tb_article(name,price,remark)
values('疯狂java讲义',108.9,'李刚老师经典著作');
insert into tb_article(name,price,remark)
values('疯狂android讲义',99.9,'李刚老师经典著作');
insert into tb_article(name,price,remark)
values('疯狂ios讲义',89.9,'李刚老师经典著作');
insert into tb_article(name,price,remark)
values('springmvc+mybatis企业开发',69.9,'肖文吉老师经典著作'); -- 订单表
create table tb_order(
id int primary key auto_increment,
code varchar(32),
total double,
user_id int,
foreign key (user_id) references tb_user(id)
); insert into tb_order(code,total,user_id)
values('6aa3fa359ff14619b77fab5990940a2d',388.6,1); insert into tb_order(code,total,user_id)
values('6aa3fa359ff14619b77fab5990940b3c',217.8,1); --创建订单表
create table tb_item(
order_id int,
article_id int,
amount int,
primary key(order_id,article_id),
foreign key (order_id) references tb_order(id),
foreign key (article_id) references tb_article(id)
); insert into tb_item(order_id,article_id,amount)
values(1,1,1);
insert into tb_item(order_id,article_id,amount)
values(1,2,1);
insert into tb_item(order_id,article_id,amount)
values(1,3,2); insert into tb_item(order_id,article_id,amount)
values(2,4,2);
insert into tb_item(order_id,article_id,amount)
values(2,1,1);
tb_order表的user_id作为外键参照tb_user表的主键id。tb_item表作为中间表,用来维护tb_article和tb_order的多对多关系,tb_item表的order_id作为外键参照tb_order表的主键id,article_id作为外键参照tb_article表的主键id。
代码中创建User对象、Order对象和Article的对象(此处省略get/set方法)
public class User implements Serializable{ private Integer id; // 用户id,主键
private String username; // 用户名
private String loginname; // 登录名
private String password; // 密码
private String phone; // 联系电话
private String address; // 收货地址 // 用户和订单是一对多的关系,即一个用户可以有多个订单
private List<Order> orders;
···
}
public class Order implements Serializable { private Integer id; // 订单id,主键
private String code; // 订单编号
private Double total; // 订单总金额 // 订单和用户是多对一的关系,即一个订单只属于一个用户
private User user; // 订单和商品是多对多的关系,即一个订单可以包含多种商品
private List<Article> articles;
···
}
public class Article implements Serializable { private Integer id; // 商品id,主键
private String name; // 商品名称
private Double price; // 商品价格
private String remark; // 商品描述 // 商品和订单是多对多的关系,即一种商品可以包含在多个订单中
private List<Order> orders;
···
}
映射文件如下
UserMapper.xml
<mapper namespace="org.zang.mapper.UserMapper"> <resultMap type="org.zang.domain.User" id="userResultMap">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="loginname" column="loginname"/>
<result property="password" column="password"/>
<result property="phone" column="phone"/>
<result property="address" column="address"/>
<!-- 一对多关联映射:collection -->
<collection property="orders" javaType="ArrayList" column="id" ofType="org.zang.domain.User"
select="org.zang.mapper.OrderMapper.selectOrderByUserId" fetchType="lazy">
<id property="id" column="id"/>
<result property="code" column="code"/>
<result property="total" column="total"/>
</collection>
</resultMap> <select id="selectUserById" parameterType="int" resultMap="userResultMap">
SELECT * FROM tb_user WHERE id = #{id}
</select> </mapper>
OrderMapper.xml
<mapper namespace="org.zang.mapper.OrderMapper"> <resultMap type="org.zang.domain.Order" id="orderResultMap">
<id property="id" column="oid"/>
<result property="code" column="code"/>
<result property="total" column="total"/>
<!-- 多对一关联映射:association -->
<association property="user" javaType="org.zang.domain.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="loginname" column="loginname"/>
<result property="password" column="password"/>
<result property="phone" column="phone"/>
<result property="address" column="address"/>
</association>
<!-- 多对多映射的关键:collection -->
<collection property="articles" javaType="ArrayList" column="oid" ofType="org.zang.domain.Article"
select="org.zang.mapper.ArticleMapper.selectArticleByOrderId" fetchType="lazy">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="price" column="price"/>
<result property="remark" column="remark"/>
</collection>
</resultMap> <!-- 注意,如果查询出来的列同名,例如tb_user表的id和tb_order表的id都是id,同名,需要使用别名区分 -->
<select id="selectOrderById" parameterType="int" resultMap="orderResultMap">
SELECT u.*,o.id AS oid,CODE,total,user_id
FROM tb_user u,tb_order o
WHERE u.id = o.user_id
AND o.id = #{id}
</select> <!-- 根据userid查询订单 -->
<select id="selectOrderByUserId" parameterType="int" resultType="org.zang.domain.Order">
SELECT * FROM tb_order WHERE user_id = #{id}
</select> </mapper>
ArticleMapper.xml
<mapper namespace="org.zang.mapper.ArticleMapper"> <select id="selectArticleByOrderId" parameterType="int" resultType="org.zang.domain.Article">
SELECT * FROM tb_article WHERE id IN (
SELECT article_id FROM tb_item WHERE order_id = #{id}
)
</select> </mapper>
相关映射的含义上面已解释,关联映射最主要的是能够用好如下两个标签:
- * 对多关联映射:collection
- * 对一关联映射:association
此外注意:一对多使用的都是lazy(懒加载)。
mybatis标签之——关联映射的更多相关文章
- Mybatis中的关联映射和查询
一.商品订单数据模型 1.数据表 这里定义了四个表,分别表示用户,商品,订单,和订单详情. 用户表user CREATE TABLE `user` ( `id` int(11) NOT NULL AU ...
- Mybatis的关联映射
实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系.针对多表之间的操作,MyBatis提供了关联映射, 通过关联映射就可以很好的处理对象与对象之间的关联关 ...
- 转:Mybatis系列之集合映射
转:Mybatis系列之集合映射 上篇文章我们讲了关联映射,实现了销售与登录用户之间的关联.本文我们接着来讲一讲集合映射,实现销售与客户的多对多关系. 实现销售与客户多对多关系 本文中仍延用<M ...
- mybatis 一对一关联映射实例
在实际项目开发中,经常存在一对一的关系,如一个人对应一张身份证信息,这就是一对一的关系.下面是一个简单的实例: 1.建表过程我就省略了,主要是一张Person表,一张IDCard表,其相关属性见步骤2 ...
- Mybatis(四)关联映射
一. Mybatis关联映射 1 讲数据库中关联关系,主键表与外键表 一对多,多对一,主键表表示一 与外键表表示多 学生与学校的关系,工人与工厂,人员与部门的关系,.... 多 一 ...
- SSM框架开发web项目系列(三) MyBatis之resultMap及关联映射
前言 在上篇MyBatis基础篇中我们独立使用MyBatis构建了一个简单的数据库访问程序,可以实现单表的基本增删改查等操作,通过该实例我们可以初步了解MyBatis操作数据库需要的一些组成部分(配置 ...
- MyBatis学习(七)MyBatis关联映射之多对多映射
对于数据库中的多对多关系建议使用一个中间表来维护关系. 1.创建四张表,分别为用户表,商品表,订单表,中间表. DROP TABLE IF EXISTS `t_user`; CREATE TABLE ...
- MyBatis的核心配置、动态sql、关联映射(快速总结)
MyBatis的核心对象和配置 #1. SqlSessionFactory对象: 单个数据库映射关系经过编译的内存镜像: 作用:创建SQLSession对象. //读取配置文件 InputSteam ...
- mybatis之关联映射
###mybatis使用之一对一关联映射 1)分析并画ER图.(特别是一对一.一对多.多对多的情况) 2)启动终端数据库,并建库建表,在表中插入值和字段,并查看结果.(后期把navicat用上) 3) ...
随机推荐
- CAShapeLayer的path动画
CAShapeLayer的path动画 效果 源码 https://github.com/YouXianMing/Animations // // CAShapeLayerPathController ...
- Android之计算两个时间的相差
参数: sdate = 2013-07-16 16:14:47 /** * 以友好的方式显示时间 * @param sdate * @return */ public static String ...
- 《马上有招儿:PPT商务演示精选20讲(全彩) 》
<马上有招儿:PPT商务演示精选20讲(全彩) > 基本信息 作者:马建强 霍然 出版社:电子工业出版社 ISBN:9787121225123 上架时间:2014-3-11 出版日期 ...
- Rsync服务介绍与配置
Rsync 简要介绍 rsync 是一个用于增量文件传输的开源工具,不得不说,rsync简直是不同服务器间传输文件.同步文件的利器.与FTP相比,它具有非常简单的安装和配置方法.而且,rsync可以只 ...
- 高效的数据压缩编码方式 Protobuf
一. protocol buffers 是什么? Protocol buffers 是一种语言中立,平台无关,可扩展的序列化数据的格式,可用于通信协议,数据存储等. Protocol buffers ...
- Spark GraphX图处理编程实例
所构建的图如下: Scala程序代码如下: import org.apache.spark._ import org.apache.spark.graphx._ // To make some of ...
- OTL翻译(5) -- otl_stream流相关绑定变量
声明绑定变量 本章节将详细的说明如何在otl_stream流里面声明绑定变量. SQL语句.SQL语句块或存储过程在程序里面使用的时候总是带有占位符.OTL里面带有一个小的解析器用来解析这些占位符,并 ...
- Informatica 常用组件Lookup之四 查找组件
在映射中配置查找转换时,请定义以下组件: 查找源 端口 属性 条件 元数据扩展 查找源 您可以使用平面文件或关系表作为查找源.创建查找转换时,您可以从以下位置导入查找源: 资料库中的任 ...
- Median of Two Sorted Array leetcode java
题目: There are two sorted arrays A and B of size m and n respectively. Find the median of the two sor ...
- _com_util::ConvertBSTRToString的使用问题
#include <comutil.h> 然后调用_com_util::ConvertBSTRToString提示如下错误: error LNK2019: unresolved exter ...