前面几节的示例基本都是一些单表查询,实际项目中,经常用到关联表的查询,比如一对一,一对多等情况。在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学习系列(五)关联查询的更多相关文章

  1. MyBatis:学习笔记(3)——关联查询

    MyBatis:学习笔记(3)--关联查询 关联查询 理解联结 SQL最强大的功能之一在于我们可以在数据查询的执行中可以使用联结,来将多个表中的数据作为整体进行筛选. 模拟一个简单的在线商品购物系统, ...

  2. MyBatis学习总结(五)——关联表查询的实现

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  3. Mybatis学习4——一对一关联查询方法2------实体作为属性

    实体order和user采用resultMap order package pojo; import java.util.Date; public class Order { private Inte ...

  4. Mybatis学习4——一对一关联查询方法1--创建实体

    创建一个实体继承两个实体之一,另一个实体作为属性 实体1. order package pojo; import java.util.Date; public class Order { privat ...

  5. Mybatis学习笔记(七) —— 关联查询

    一.一对多查询 需求:查询所有订单信息,关联查询下单用户信息. 注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询.如果从用户信息出发查询用户下的订单信息则 ...

  6. mybatis学习系列五--插件及类型处理器

    2 插件编写(80-81) 单个插件编写 2.1实现interceptor接口(ibatis) invocation.proceed()方法执行必须要有,否则不会无法实现拦截作用 2.2 使用@int ...

  7. 【Mybatis】MyBatis之表的关联查询(五)

    本章介绍Mybatis之表的关联查询 一对一关联 查询员工信息以及员工的部门信息 1.准备表employee员工表,department部门表 CREATE TABLE `employee` ( `i ...

  8. MyBatis学习系列三——结合Spring

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...

  9. MyBatis学习系列二——增删改查

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 数据库的经典操作:增删改查. 在这一章我们主要说明一下简单的查询和增删改, ...

  10. MyBatis学习系列一之环境搭建

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 学习一个新的知识,首先做一个简单的例子使用一下,然后再逐步深入.MyBat ...

随机推荐

  1. 高级同步器:交换器Exchanger

    引自:https://blog.csdn.net/Dason_yu/article/details/79764467 一.定义每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹 ...

  2. Hadoop(14)-MapReduce框架原理-切片机制

    1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...

  3. STM32CubeMx配置SPI注意的一个问题

    这样配置SPI引脚 然后这样配置SPI参数 生成立这样的配置代码 /* SPI2 init function */static void MX_SPI2_Init(void){ /* SPI2 par ...

  4. (数据科学学习手札22)主成分分析法在Python与R中的基本功能实现

    上一篇中我们详细介绍推导了主成分分析法的原理,并基于Python通过自编函数实现了挑选主成分的过程,而在Python与R中都有比较成熟的主成分分析函数,本篇我们就对这些方法进行介绍: R 在R的基础函 ...

  5. python的初体验

    最近由于毕业答辩,导致一些博客没有更新,见谅,今天我们开始一些新的内容 1.python的注释 单行注释:# 多行注释: ''' 这是多行注释 我们可以在里面写很多很多的行 ''' 2.编码风格 #c ...

  6. JavaScript---设计模式简介

    概念 设计模式(Design pattern)是一套被反复使用.思想成熟.经过分类和无数次实战设计经验的总结的.使用设计模式是为了让系统代码可重用.可扩展.可解耦.更容易被人理解且能保证代码的可靠性. ...

  7. struts2官方 中文教程 系列十一:使用XML进行表单验证

    在本教程中,我们将讨论如何使用Struts 2的XML验证方法来验证表单字段中用户的输入.在前面的教程中,我们讨论了在Action类中使用validate方法验证用户的输入.使用单独的XML验证文件让 ...

  8. 2 web服务器:固定返回值

    1.老师给的思路 #tcp socket 服务端 socket = socket.socket() socket.bind() socket.listen() client_socket = sock ...

  9. 5.hbase表新增数据同步之add_peer

    一.前提主从集群之间能互相通讯: 二.在cluster1上(源集群):  1.查看集群已开启的peers hbase(main):011:0> list_peers PEER_ID CLUSTE ...

  10. XStream轻松转换xml和java对象

    首先引入所需的jar: xstream-1.4.9.xpp3_min-1.1.4c.dom4j-1.6.1, 或用maven管理jar包时在pom.xml中添加: <!-- https://mv ...