前面几节的示例基本都是一些单表查询,实际项目中,经常用到关联表的查询,比如一对一,一对多等情况。在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. DLL DEF文件编写方法 VC++ 调用、调试DLL的方法 显式(静态)调用、隐式(动态)调用

    DLL 文件编写方法: 1.建立DLL工程 2.声明.定义要导出的函数 BOOL WINAPI InitDlg( HWND hTabctrl,TShareMem* pTshare,CRect* prc ...

  2. ABAP术语-Function Builder

    Function Builder 原文:http://www.cnblogs.com/qiangsheng/archive/2008/02/03/1063196.html Tool for creat ...

  3. oracle的局部本地分区索引

    环境:oracle 12.2.0.1 注:未确定10g,11g是否有这些特性.现在基本不用10g,主要用12c,11g. 毫无疑问,这种 特性对于dba或者实施人员而言显得很重要,尤其当你的数据库主要 ...

  4. MyEclipse格式化JSP代码,其中Javascript无法格式化的原因

    MyEclipse格式化JSP代码,其中Javascript无法格式化的原因: 可能是JSP页面代码有错误的地方,而且可能是一个很微小的错误,比如多写了一个标点符号,这个需要仔细检查,包括HTML.C ...

  5. 启用image-filter扩展模块

    进入lnmp目录打开lnmp.conf配置文件 修改Nginx_Modules_Options=' --prefix=/usr/local/nginx --with-http_image_filter ...

  6. .net core 发布到docker

    1. 安装docker-desktop,windows环境安装包 官方网站:https://www.docker.com/ 2.注册登陆Docker账号 安装成功后,在官方网站注册一个账号,使用账号登 ...

  7. React学习(1)—— 基础项目搭建以及环境配置

    首先,我们需要安装node.js,直接搜索并在官网下载安装包. node.js官网:https://nodejs.org/en/ 现在我们成功安装了node和npm,然后我们来用npm创建新的项目,首 ...

  8. java递归 斐波那契数列递归与非递归实现

    递归简单来说就是自己调用自己, 递归构造包括两个部分: 1.定义递归头:什么时候需要调用自身方法,如果没有头,将陷入死循环 2.递归体:调用自身方法干什么 递归是自己调用自己的方法,用条件来判断调用什 ...

  9. Java学习笔记一:三步搭建Java开发环境

    Java开发环境搭建 一:安装JDK: 1.下载地址:http://www.oracle.com/technetwork/java/javase/downloads 非常显眼的下载界面 2.点击下载后 ...

  10. BGP(边界网关协议)简述

    BGP的起源 不同自治系统(路由域)间路由交换与管理的需求推动了EGP的发展,但是EGP的算法简单,无法选路,从而被BGP取代. 自治系统:(AS) IGP:自治系统内部协议,ospf,rip,is- ...