Mybatis学习系列(五)关联查询
前面几节的示例基本都是一些单表查询,实际项目中,经常用到关联表的查询,比如一对一,一对多等情况。在Java实体对象中,一对一和一对多可是使用包装对象解决,属性使用List或者Set来实现,在mybatis中一对一和一对多可是使用association或者collection标签来配合实现。
在MyBatis中有两种方式实现关联查询:
1. 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。首先,然让我们来查看这个元素的属性。所有的你都会看到,它和普通的只由 select 和resultMap 属性的结果映射不同
2. 嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型
一对一查询
示例:商品表products 和 商品分类category 一个商品对应一种分类,所以products->category是一对一的关系
1.嵌套结果实现(resultMap):
通过resultMap将查询结果中商品信息映射到Product对象中,在Product类中添加属性category,将关联结果映射到Product.category属性上。
<!-- 一对一查询 关联查询 使用resultMap映射结果集 -->
<select id="oneToOneTestMap" parameterType="int" resultMap="productInfoMap">
select p.*,c.id
categoryId,c.name categoryName,c.remark categoryRemark
from products p
join category c
on p.categoryId= c.Id
where p.id
=#{value}
</select>
<resultMap id="productInfoMap" type="com.sl.po.Product">
<id column="id" property="Id" />
<result column="name" property="Name" />
<result column="description" property="Description" />
<result column="unitprice" property="UnitPrice" />
<result column="imageUrl" property="ImageUrl" />
<result column="isnew" property="IsNew" />
<result column="citycode" property="cityCode" /> <!-- association:用于映射关联查询单个对象的信息
property:要将关联查询的分类信息映射到属性category上
-->
<association property="category" javaType="com.sl.po.Category">
<id column="categoryId" property="Id" />
<result column="categoryName" property="Name" />
<result column="categoryRemark" property="Remark" />
</association>
</resultMap>
注:也可以使用resultType配置实现,需要定义一个包装类含有product和category两个对象的属性即可。
2.嵌套查询实现
<!-- 关联嵌套查询 -->
<select id="oneToOneTestAssociationSelect" parameterType="int" resultMap="productInfoMap2">
select p.*
from products p
where p.id =#{value}
</select>
<resultMap id="productInfoMap2" type="com.sl.po.Product" >
<id column="id" property="Id" />
<result column="name" property="Name" />
<result column="description" property="Description" />
<result column="unitprice" property="UnitPrice" />
<result column="imageUrl" property="ImageUrl" />
<result column="isnew" property="IsNew" />
<result column="citycode" property="cityCode" />
<!-- column:传递子查询参数,如果要处理符复合主键,使用column= "{prop1=col1,prop2=col2}" -->
<!-- select:子查询语句id -->
<association property="category" javaType="com.sl.po.Category" column="categoryId" select="selectCategoryInfo">
</association>
</resultMap>
<!-- 子查询 -->
<select id="selectCategoryInfo" parameterType="int" resultType="com.sl.po.Category">
select * from category where id=#{id}
</select>
使用resultType、resultMap和嵌套查询对比分析:
resultType:使用resultType只需要将查询结果集中的列名与定义的pojo属性一一对应即可完成映射,缺点:resultType无法将查询结果映射到包装类的pojo属性中
resultMap:需要额外定义resultMap,在resultMap中将结果集列名与pojo对象属性一一配置。
嵌套查询:需要定义多个查询,上面示例定义两个查询,一个用于查询products表,一个用于查询category表。由于使用的是嵌套查询,当操作大型数据集合和列表时将会带来频繁操作数据库问题。即执行一条sql获取结果集(oneToOneTestAssociationSelect),根据该结果集,循环执行嵌套查询获取具体信息(selectCategoryInfo),与上面的嵌套结果查询相比,这种情况显然有明显不足。
3. 测试代码
定义Product和Category实体,添加Mapper接口
package com.sl.po;
import java.math.BigDecimal;
public class Product {
private int Id;
private String Name;
private String Description;
private BigDecimal UnitPrice;
private String ImageUrl;
private Boolean IsNew;
private String cityCode;
private int categoryId;
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public int getCategoryId() {
return categoryId;
}
public void setCategoryId(int categoryId) {
this.categoryId = categoryId;
}
public String getCityCode() {
return cityCode;
}
public void setCityCode(String cityCode) {
this.cityCode = cityCode;
}
public int getId() {
return Id;
}
public void setId(int id) {
this.Id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
this.Name = name;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
this.Description = description;
}
public BigDecimal getUnitPrice() {
return UnitPrice;
}
public void setUnitPrice(BigDecimal unitprice) {
this.UnitPrice = unitprice;
}
public String getImageUrl() {
return Name;
}
public void setImageUrl(String imageurl) {
this.ImageUrl = imageurl;
}
public boolean getIsNew() {
return IsNew;
}
public void setIsNew(boolean isnew) {
this.IsNew = isnew;
}
@Override
public String toString() {
return "Product [Id=" + Id + ", Name=" + Name + ", Description=" + Description + ", UnitPrice=" + UnitPrice
+ ", ImageUrl=" + ImageUrl + ", IsNew=" + IsNew + ", cityCode=" + cityCode + ", categoryId="
+ categoryId + ", category=" + category + "]";
}
}
package com.sl.po;
import java.util.List;
public class Category {
private int Id;
private String Name;
private String Remark;
private List<Product> productList;
public int getId() {
return Id;
}
public List<Product> getProductList() {
return productList;
}
public void setProductList(List<Product> productList) {
this.productList = productList;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getRemark() {
return Remark;
}
public void setRemark(String remark) {
Remark = remark;
}
@Override
public String toString() {
return "Category [Id=" + Id + ", Name=" + Name + ", Remark=" + Remark + ", productList=" + productList + "]";
}
}
// 一对一 使用resultType映射结果集
// @Test
public void testSelectProduct() { // 获取mapper接口的代理对象
UnitMapper unitMapper = session.getMapper(UnitMapper.class); ProductDetailInfo detailInfo = unitMapper.oneToOneTest(1); System.out.println(detailInfo); // 关闭会话
session.close();
} // 一对一 使用resultMap映射结果集
// @Test
public void testSelectProduct2() { // 获取mapper接口的代理对象
UnitMapper unitMapper = session.getMapper(UnitMapper.class); Product product = unitMapper.oneToOneTestMap(2); System.out.println(product); System.out.println(product.getCategory().toString()); // 关闭会话
session.close();
} //嵌套查询
//一对一 //@Test
public void testSelectProductTest() { // 获取mapper接口的代理对象
UnitMapper unitMapper = session.getMapper(UnitMapper.class); Product product = unitMapper.oneToOneTestAssociationSelect(2); System.out.println(product); System.out.println(product.getCategory().toString()); // 关闭会话
session.close();
}
一对多查询
将上面一对一的示例倒过来看,一种类别下有多个商品,所以category->products是一对多的关系
mybatis中可以通过使用resultMap的collection标签将关联查询的多条记录映射到一个list集合属性中。
1.嵌套结果实现
<!-- 一对多映射 -->
<select id="oneToManyTest" resultMap="categoryInfo">
select c.id cid,c.`name`
cname,c.remark, p.*
from category c
join products p
on p.categoryId= c.Id
where c.id= #{cid}
</select>
<resultMap type="com.sl.po.Category" id="categoryInfo">
<id column="cid" property="id" />
<result column="cname" property="name" />
<result column="remark" property="remark" />
<!-- collection标签,一对多映射,关联当前分类下产品信息 property映射集合结果,ofType结果集类型 -->
<collection property="productList" ofType="com.sl.po.Product">
<id property="id" column="id" javaType="int" jdbcType="INTEGER" />
<result column="name" property="Name" />
<result column="description" property="Description" />
<result column="unitprice" property="UnitPrice" />
<result column="imageUrl" property="ImageUrl" />
<result column="isnew" property="IsNew" />
<result column="citycode" property="cityCode" />
</collection>
</resultMap>
2.嵌套查询实现
<!-- 集合嵌套查询 -->
<select id="oneToManyTestCollectionSelect" resultMap="categoryInfo2">
select *
from category c
where c.id= #{id}
</select>
<resultMap id="categoryInfo2" type="com.sl.po.Category">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="remark" property="remark" />
<!--collection 映射一对多结果集 column:传递嵌套查询参数 select:嵌套查询id-->
<collection property="productList" ofType="com.sl.po.Product" column="id" select="selectProductByCategoryId">
</collection>
</resultMap>
<!-- 嵌套子查询 -->
<select id="selectProductByCategoryId" resultType="com.sl.po.Product">
select *
from products
where categoryId= #{id}
</select>
测试代码:
定义Product和Category实体同上,添加Mapper接口
public interface UnitMapper {
Category oneToManyTest(int cId);
Product oneToOneTestAssociationSelect(int id);
//嵌套查询中的子查询也需要定义接口
Category selectCategoryInfo(int id);
}
//一对多
@Test
public void oneToManyTest() { UnitMapper unitMapper = session.getMapper(UnitMapper.class); Category catrgoryInfo = unitMapper.oneToManyTest(1); System.out.println(catrgoryInfo); if (catrgoryInfo.getProductList().size() > 0) {
for (Product pro : catrgoryInfo.getProductList()) {
System.out.println(pro);
}
} // 关闭会话
session.close(); } //嵌套查询 一对多
@Test
public void testoneToManyTestCollectionSelect() { // 获取mapper接口的代理对象
UnitMapper unitMapper = session.getMapper(UnitMapper.class); Category category = unitMapper.oneToManyTestCollectionSelect(1); System.out.println(category); if (category.getProductList().size() > 0) {
for (Product pro : category.getProductList()) {
System.out.println(pro);
}
}
// 关闭会话
session.close();
}
多对多查询
示例:一个订单包含多个商品,一个商品也可以对应多个订单,这个示例查询稍微扩展一下,增加用户信息,一个用户对应多个订单
实体对象定义:定义User实体,增加orders属性,用于映射当前用户的订单; 定义Order对象,增加orderItems属性,映射当前订单有哪些内容(产品);定义OrderItem实体,增加product属性,映射具体产品信息
<!-- 多对多映射 查询用户信息及对应订单信息,订单详情 -->
<!-- select * from orders o join `user` u on o.userId = u.id join orderItem
i on o.Id = i.orderid join products p on i.productid = p.Id -->
<select id="manyToManyTest" resultMap="userAndOrderInfo">
select u.*,
o.id oid,
o.createtime ocreatetime,
o.userid ouserid,
o.amount oamount,
o.remark
oremark,
i.id iid,
i.orderid iorderid,
i.productid iproductid,
i.createtime icreatetime,
i.number inumber,
i.price iprice, p.id pid,
p.`name` pname,
p.Description pdescription from orders o
join `user` u on
o.userId = u.id
join orderItem i on o.Id = i.orderid
join products p on
i.productid = p.Id
where u.id=#{id}
</select>
<resultMap type="com.sl.po.User" id="userAndOrderInfo">
<id column="id" property="id" />
<result column="sex" property="sex" />
<result column="birthday" property="birthday" />
<result column="address" property="address" />
<result column="username" property="userName" />
<!-- 映射用户对应的订单信息,一个用户可以有多个订单 -->
<collection property="orders" ofType="com.sl.po.Order">
<id column="oid" property="id" />
<result column="ocreatetime" property="createTime" />
<result column="ouserid" property="userId" />
<result column="oamount" property="amount" />
<result column="oremark" property="remark" />
<!-- 订单对应的商品信息,一个订单可以有多个商品 -->
<collection property="orderItems" ofType="com.sl.po.OrderItem">
<id column="iid" property="id" />
<result column="iorderid" property="orderId" />
<result column="iproductid" property="productId" />
<result column="icreatetime" property="createTime" />
<result column="inumber" property="number" />
<result column="iprice" property="price" />
<!-- 映射商品信息 (OrderItem与商品product 一一对应)-->
<association property="product" javaType="com.sl.po.Product">
<id column="pid" property="Id" />
<result column="pname" property="Name" />
<result column="pdescription" property="Description" />
</association>
</collection>
</collection>
</resultMap>
测试代码
package com.sl.po; import java.sql.Date;
import java.util.List; public class User { private int id;
private String sex;
private Date birthday;
private String address;
private String userName; //映射当前用户订单列表
private List<Order> orders; public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
} @Override
public String toString() {
return "User [id=" + id + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + ", userName="
+ userName + ", orders=" + orders + "]";
} }
package com.sl.po; import java.sql.Date;
import java.util.List; public class Order { private int id;
private int userId;
private Date createTime;
private int amount;
private String remark; private User user;
//映射订单内容(产品信息)
private List<OrderItem> orderItems; public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
} }
package com.sl.po;
public class OrderItem {
private int id;
private int orderId;
private int productId;
private int createTime;
private int number;
private int price;
//订单项对应的具体产品
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public int getCreateTime() {
return createTime;
}
public void setCreateTime(int createTime) {
this.createTime = createTime;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
package com.sl.mapper; import java.util.List; import com.sl.po.Category;
import com.sl.po.Product;
import com.sl.po.ProductDetailInfo;
import com.sl.po.User; public interface UnitMapper { User manyToManyTest(int id);
}
//多对多
@Test
public void manyToManyTest() { UnitMapper unitMapper = session.getMapper(UnitMapper.class); User userOrder = unitMapper.manyToManyTest(1); System.out.println(userOrder); // 关闭会话
session.close(); }
标签即属性说明
Association标签: 作用是可以将关联查询信息映射到一个pojo对象中
collection标签: 作用是可以将关联查询信息映射到一个集合中
Association和collection标签常用到的属性:
Property属性: 指定当前association标签内容映射到pojo对象中哪个属性。
javaType:映射属性的类型
typeHandler:类型处理器,使用这个属性,你可以覆盖默认的 typeHandler 类型处理器。 这个属性值是类的完全限定名或者是一个类型处理器的实现, 或者是类型别名
column:sql结果集列名,用在嵌套查询时传递参数,要 处 理 复 合 主 键 , 你 可 以 指 定 多 个 列 名 通 过 column= ” {prop1=col1,prop2=col2} ” 这种语法来传递给嵌套查询语 句。prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。
select:嵌套查询映射语句的ID
fetchType:可选的。有效值为 lazy和eager。 如果使用了,它将取代全局配置参数lazyLoadingEnabled
columnPrefix:将含有指定前缀的结果集映射到当前标签下 例如:<association property="productInfo" columnPrefix="p_" /> 将结果集中以“p_”开头的列映射到productInfo属性上
Mybatis学习系列(五)关联查询的更多相关文章
- MyBatis:学习笔记(3)——关联查询
MyBatis:学习笔记(3)--关联查询 关联查询 理解联结 SQL最强大的功能之一在于我们可以在数据查询的执行中可以使用联结,来将多个表中的数据作为整体进行筛选. 模拟一个简单的在线商品购物系统, ...
- MyBatis学习总结(五)——关联表查询的实现
一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...
- Mybatis学习4——一对一关联查询方法2------实体作为属性
实体order和user采用resultMap order package pojo; import java.util.Date; public class Order { private Inte ...
- Mybatis学习4——一对一关联查询方法1--创建实体
创建一个实体继承两个实体之一,另一个实体作为属性 实体1. order package pojo; import java.util.Date; public class Order { privat ...
- Mybatis学习笔记(七) —— 关联查询
一.一对多查询 需求:查询所有订单信息,关联查询下单用户信息. 注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询.如果从用户信息出发查询用户下的订单信息则 ...
- mybatis学习系列五--插件及类型处理器
2 插件编写(80-81) 单个插件编写 2.1实现interceptor接口(ibatis) invocation.proceed()方法执行必须要有,否则不会无法实现拦截作用 2.2 使用@int ...
- 【Mybatis】MyBatis之表的关联查询(五)
本章介绍Mybatis之表的关联查询 一对一关联 查询员工信息以及员工的部门信息 1.准备表employee员工表,department部门表 CREATE TABLE `employee` ( `i ...
- MyBatis学习系列三——结合Spring
目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...
- MyBatis学习系列二——增删改查
目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 数据库的经典操作:增删改查. 在这一章我们主要说明一下简单的查询和增删改, ...
- MyBatis学习系列一之环境搭建
目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 学习一个新的知识,首先做一个简单的例子使用一下,然后再逐步深入.MyBat ...
随机推荐
- 高级同步器:交换器Exchanger
引自:https://blog.csdn.net/Dason_yu/article/details/79764467 一.定义每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹 ...
- Hadoop(14)-MapReduce框架原理-切片机制
1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...
- STM32CubeMx配置SPI注意的一个问题
这样配置SPI引脚 然后这样配置SPI参数 生成立这样的配置代码 /* SPI2 init function */static void MX_SPI2_Init(void){ /* SPI2 par ...
- (数据科学学习手札22)主成分分析法在Python与R中的基本功能实现
上一篇中我们详细介绍推导了主成分分析法的原理,并基于Python通过自编函数实现了挑选主成分的过程,而在Python与R中都有比较成熟的主成分分析函数,本篇我们就对这些方法进行介绍: R 在R的基础函 ...
- python的初体验
最近由于毕业答辩,导致一些博客没有更新,见谅,今天我们开始一些新的内容 1.python的注释 单行注释:# 多行注释: ''' 这是多行注释 我们可以在里面写很多很多的行 ''' 2.编码风格 #c ...
- JavaScript---设计模式简介
概念 设计模式(Design pattern)是一套被反复使用.思想成熟.经过分类和无数次实战设计经验的总结的.使用设计模式是为了让系统代码可重用.可扩展.可解耦.更容易被人理解且能保证代码的可靠性. ...
- struts2官方 中文教程 系列十一:使用XML进行表单验证
在本教程中,我们将讨论如何使用Struts 2的XML验证方法来验证表单字段中用户的输入.在前面的教程中,我们讨论了在Action类中使用validate方法验证用户的输入.使用单独的XML验证文件让 ...
- 2 web服务器:固定返回值
1.老师给的思路 #tcp socket 服务端 socket = socket.socket() socket.bind() socket.listen() client_socket = sock ...
- 5.hbase表新增数据同步之add_peer
一.前提主从集群之间能互相通讯: 二.在cluster1上(源集群): 1.查看集群已开启的peers hbase(main):011:0> list_peers PEER_ID CLUSTE ...
- XStream轻松转换xml和java对象
首先引入所需的jar: xstream-1.4.9.xpp3_min-1.1.4c.dom4j-1.6.1, 或用maven管理jar包时在pom.xml中添加: <!-- https://mv ...