概述
8. MyBatis嵌套查询 - 一对一 - 一对多
前言
在上一篇中我们已经基本认识了 MyBatis 的多表查询了。那么 MyBatis 还有一个比较有意思的功能,就是 嵌套查询。 这个功能有些类似 SQL 的多表联合查询,但是又不是。下面我们来认识一下。
什么是嵌套查询
嵌套查询就是将原来多表的联合查询语句拆成 多个单表的查询,再使用mybatis的语法嵌套在一起。
举个栗子
* 需求:查询一个订单,与此同时查询出该订单所属的用户
* 1. SQL 关联查询:
select * from orders o inner join user u on o.uid = u.id where o.id = 1;
* 缺点:
sql语句编写难度大
如果表中数据量大,笛卡尔积数量倍增,可能造成内存溢出
* 2. MyBatis 嵌套查询:
a.根据订单id查询订单表
select * from orders where id = 1;
// 查到订单id=1的订单信息 (uid=41)
// 结果映射到 orders对象中
b.再根据订单表中uid(外键)查询用户表
select * from user where id = 订单表uid;
// 结果映射到 orders.user 中
c.最后由mybatis框架进行嵌套组合
跟子查询的区别
1. 嵌套查询分别执行两句sql : 又有订单信息,又有对应的用户信息
2. 子查询执行一句 : 只能查到 订单编号为1的所属的用户信息
select * from user where id = (select uid from orders where id = 1)
* 优点:
sql语句编写简单
没有多表关联,不会产生笛卡尔积, 特别是在表数据比较多的情况, 更有优势
看了上面的说明之后,下面来写写具体案例。
一对一【嵌套查询】
需求
需求:查询一个订单,与此同时查询出该订单所属的用户
sql语句
-- 1.根据订单id查询订单表
select * from orders where id = 1;
-- 2.再根据订单表中uid(外键)查询用户表
select * from user where id = 41;
执行过程:
下面我们来看看具体实现代码。
案例实现
1. 编写OrderMapper接口:编写查询 Orders 的接口方法 findOrderByIdWithUser
public interface OrdersMapper {
/*
一对一关系
# 查询id=?的订单以及对应的用户
select * from orders o inner join user u
on o.uid = u.id
where o.id = ?;
1. 参数类型: Integer id
2. 返回值类型 Orders
# 修改成嵌套查询
1. 先查订单id=1 的订单信息 (uid=41)
select * from orders where id = ? // 订单id
2. 查uid=41的用户信息
select * from user where id = ? // 用户id
3. 两个结果嵌套一起: 映射到 orders
* */
Orders findOrderByIdWithUser(Integer id);
}
2. 编写OrderMapper映射:映射 findOrderByIdWithUser 查询方法
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lijw.dao.OrdersMapper">
<!--
设置查询结果集 resultMap, 结果映射为 Orders 类
-->
<resultMap id="myorder" type="Orders" autoMapping="true">
<!-- 设置 id 字段映射 Orders 类的属性 id -->
<id property="id" column="id"/>
<!-- 设置普通字段 ordertime 映射 Orders 类的属性 ordertime -->
<result property="ordertime" column="ordertime"/>
<!--
# 嵌套查询重点:
0. 目的
select * from user where id = ?
映射到 orders.user属性中
1. 编写查询user表的语句:
UserMapper.findUserById -> UserMapper.xml
2. 嵌套到这里
association标签的两个属性
a. column : 条件 (执行查询方法的参数)
b. select : 调用第二句sql执行
接口的权限定名.方法名
UserMapper.findUserById(用户id)
-->
<association property="user" javaType="user" autoMapping="true"
column="uid"
select="com.lijw.dao.UserMapper.findUserById">
<id property="id" column="uid"/>
<result property="username" column="username"/>
</association>
</resultMap>
<select id="findOrderByIdWithUser" resultMap="myorder">
select * from orders where id = #{id}
</select>
</mapper>
3. 编写 UserMapper接口:设置根据 id 查询 user 表的方法
public interface UserMapper {
/*
* select * from user where id = ?
* 1. 参数: Integer id 用户标号
* 2. 返回值: User
* */
User findUserById(Integer id);
}
4. UserMapper映射:编写映射 SQL
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
实体类的映射文件
namespace 指定接口的类全名
-->
<mapper namespace="com.lijw.dao.UserMapper">
<select id="findUserById" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
5. 通过mybatis进行嵌套组合
看 OrderMapper.xml里的嵌套设置
一对一在结果映射 resultMap 中使用 association 进行嵌套查询,column
为传递的从 Orders 数据中查询出来的 uid
.
6. 测试
public class OrderMapperTest{
@Test
public void test02(){
SqlSession session = MyBatisUtil.getSqlSession();
OrdersMapper mapper = session.getMapper(OrdersMapper.class);
// 订单编号 = 1
Orders orders = mapper.findOrderByIdWithUser(1);
System.out.println("订单:" + orders);
MyBatisUtil.commitAndClose(session);
}
}
一对多【嵌套查询】
需求
需求:查询一个用户,与此同时查询出该用户具有的订单
sql语句
-- 1. 先根据用户id,查询用户表(一个)
SELECT * FROM `user` WHERE id = 41;
-- 2. 再根据用户id,查询订单表(多个)
SELECT * FROM orders WHERE uid = 41;
执行如下:
案例实现
1. OrderMapper接口:编写根据 id 查询该用户 User 下的订单 Orders 的方法
public interface OrderMapper {
/**
* # 查询id=? 的用户以及拥有的订单
* select * from user u inner join orders o
on u.id = o.uid
where u.id = ?;
* 1. 参数类型: Integer
* 2. 返回值类型: User
* <p>
* # 修改成嵌套查询
* a. 查询用户id=? 的用户
* select * from user where user.id = ?;
* <p>
* b. 查询该用户的订单信息
* select * from orders where uid = ?;
* <p>
* c. 嵌套
*/
User findUserByIdWithOrders(Integer uid);
}
2. OrderMapper映射:编写映射 SQL
<!-- 根据id查询订单Orders的用户信息 -->
<resultMap id="myuser" type="user" autoMapping="true">
<id property="id" column="id"/>
<!--
collection: 为一对多的查询存储方式
查询对应的订单信息 -> user.list中
column : 条件(结果集字段作为查询语句的参数)
-->
<collection property="list" ofType="orders" autoMapping="true"
column="id"
select="com.lijw.dao.OrdersMapper.findOrdersByUid">
<id property="id" column="oid"/>
</collection>
</resultMap>
<select id="findUserByIdWithOrders" resultMap="myuser">
select * from user where user.id = #{uid}
</select>
3. 编写第二句sql的接口和映射文件
public interface OrderMapper {
/*
* select * from orders where uid = ?;
*
* 参数类型: Integer id
* 返回值类型: List<Orders>
* */
List<Orders> findOrdersByUid(Integer uid);
}
<!-- 根据uid查询订单信息 -->
<select id="findOrdersByUid" resultType="orders">
select * from orders where uid = #{uid}
</select>
4. 通过mybatis进行嵌套组合
查看OrderMapper.xml文件
5. 测试
public class UserMapperTest extends BaseMapperTest {
// 一对多嵌套查询测试
@Test
public void test03(){
SqlSession session = MyBatisUtil.getSqlSession();
OrdersMapper mapper = session.getMapper(OrdersMapper.class);
// 查询用户id=41的用户以及拥有的订单
User user = mapper.findUserByIdWithOrders(41);
System.out.println(user);
MyBatisUtil.commitAndClose(session);
}
}
小结
* 步骤:一对多举例
1)先查询(一方)单表
2)再查询(多方)单表
3)最后由mybatis嵌套组合
一对一配置:使用<resultMap>+<association>做配置,通过column条件,执行select查询
一对多配置:使用<resultMap>+<collection>做配置,通过column条件,执行select查询
优点:1.简化sql语句编写、2.不会产生笛卡尔积
缺点: 执行两遍
开发中到底使用哪一种?
传统开发,数据量小:使用联合查询(执行一次,传输一次)
互联网开发,数据量大:使用嵌套查询 (执行两次,但是只需要传输一次)
当前也有人这么玩(知道):
在java中先查用户,在查角色,不在使用嵌套....(执行两次,需要传输两次)
最后
以上就是甜美小蝴蝶为你收集整理的8. MyBatis嵌套查询 - 一对一 - 一对多8. MyBatis嵌套查询 - 一对一 - 一对多的全部内容,希望文章能够帮你解决8. MyBatis嵌套查询 - 一对一 - 一对多8. MyBatis嵌套查询 - 一对一 - 一对多所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复