第9章 MyBatis的关联映射
学习目标
● 了解数据表之间以及对象之间的三种关联关系
● 熟悉关联关系中的嵌套查询和嵌套结果
● 掌握一对一、一对多和多对多关联映射的使用
9.1 关联关系概述
· 一对一:在任意一方引入对方主键作为外键。
· 一对多:在“多”的一方,添加“一”的一方的主键作为外键。
· 多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。

9.2 一对一
在<association>元素中,通常可以配置以下属性。
· property:指定映射到的实体类对象属性,与表字段一一对应。
· column:指定表中对应的字段。
· javaType:指定映射到实体对象属性的类型。
· select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询。
· fetchType:指定在关联查询时是否启用延迟加载。fetchType属性有lazy和eager两个属性值,默认值为lazy(即默认关联映射延迟加载)。
<!--嵌套查询-->
<association property="card" column="card_id" select="com.itheima.mapper.IdCardMapper.findCodeById"
javaType="com.itheima.po.IdCard"/>
<!--嵌套结果-->
<association property="card" javaType="com.itheima.po.IdCard">
<id property="id" column="card_id"/>
<result property="code"column="code"/>
</association>
嵌套查询是指通过执行另外一条SQL映射语句来返回预期的复杂类型;
嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集
1.建表
Unknown column '’女’' in 'field list'
错误原因:’
修改方法:'
2.导入相关依赖
3.持久化类
4.mapper文件
<mapper namespace="com.itheima.mapper.IdCardMapper">
<!-- 根据id查证件信息-->
<select id="findCodeById" parameterType="Integer" resultType="com.itheima.po.IdCard">
select * from tb_idcard where id = #{id}
</select>
</mapper>
<mapper namespace="com.itheima.mapper.PersonMapper">
<!-- 嵌套查询:通过执行另外一条sql映射语句来返回预期的特殊类型-->
<select id="findPersonById" parameterType="Integer" resultMap="IdCardWithPersonResult">
select * from tb_person where id = #{id}
</select>
<resultMap id="IdCardWithPersonResult" type="com.itheima.po.Person">
<id property="name" column="name"/>
<id property="age" column="age" />
<id property="sex" column="sex" />
<!-- 一对一:association使用select属性引入另外一条sql语句-->
<association property="card" column="card_id" javaType="com.itheima.po.IdCard"
select="com.itheima.mapper.IdCardMapper.findCodeById"/>
</resultMap>
</mapper>
嵌套查询的方法是先执行一个简单的SQL语句,然后在进行结果映射时,将关联对象在<association>元素中使用select属性执行另一条SQL语句(即IdCardMapper.xml中的SQL)。
MyBatis嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大地消耗数据库性能并且会降低查询效率。
<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集-->
<select id="findPersonById2" parameterType="integer" resultMap="IdCardWithPersonResult2">
select p.*,idcard.code
from tb_person p ,tb_idcard idcard
where p.card_id=idcard.id
and p.id=#{id}
</select>
<resultMap id="IdCardWithPersonResult2" type="com.itheima.po.Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<association property="card" javaType="com.itheima.po.IdCard">
<id property="id" column="card_id"/>
<result property="code" column="code"/>
</association>
</resultMap>
MyBatis嵌套结果的方式只编写了一条复杂的多表关联的SQL语句,并且在<association>元素中继续使用相关子元素进行数据库表字段和实体类属性的一一映射
5.mybatis-config
<mappers>
<mapper resource="com/itheima/mapper/IdCardMapper.xml"/>
<mapper resource="com/itheima/mapper/PersonMapper.xml"/>
</mappers>
6.测试
用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率,默认没有开启延迟加载。
<settings>
<! -- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<! -- 将积极加载改为消息加载,即按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
在映射文件中,MyBatis关联映射的<association>元素和<collection>元素中都已默认配置了延迟加载属性,即默认属性fetchType="lazy"(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无须在映射文件中再做配置。
9.3 一对多
<resultMap>元素中,包含了一个<collection>子元素,MyBatis就是通过该元素来处理一对多关联关系的。<collection>子元素的属性大部分与<association>元素相同,但其还包含一个特殊属性——ofType。ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型。
<! --方式一:嵌套查询 -->
<collection property="ordersList" column="id"
ofType="com.itheima.po.Orders"
select=" com.itheima.mapper.OrdersMapper.selectOrders" />
<! --方式二:嵌套结果 -->
<collection property="ordersList" ofType="com.itheima.po.Orders">
<id property="id" column="orders_id" />
<result property="number" column="number" />
</collection>
1.建表
2.持久化类
3.mapper文件
<mapper namespace="com.itheima.mapper.UserMapper1">
<!-- 一对多:查看某一用户及其关联的订单信息-->
<!-- 注意:当关联查询出的列名相同,则需要使用别名区分-->
<select id="findUserWithOrders" parameterType="integer" resultMap="UserWithOrdersResult">
select u.* , o.id as orders_id,o.number
from tb_user u , tb_orders o
where u.id = o.user_id
and u.id = #{id}
</select>
<resultMap id="UserWithOrdersResult" type="com.itheima.po.User1">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<!-- 一对多关联映射:collection-->
<!-- ofType表示属性集合中元素的类型 List<Orders>属性及Order类-->
<collection property="ordersList" ofType="com.itheima.po.Orders">
<id property="id" column="orders_id"/>
<result property="number" column="number" />
</collection>
</resultMap>
</mapper>
4.mybatis-config
<mappers>
<mapper resource="com/itheima/mapper/UserMapper1.xml"/>
</mappers>
5.测试
@Test
public void findUserTest(){
SqlSession session = MybatisUtils.getSession();
User1 user = session.selectOne("com.itheima.mapper.UserMapper1.findUserWithOrders", 1);
System.out.println(user);
session.close();
}
上述案例从用户的角度出发,用户与订单之间是一对多的关联关系,但是从订单角度出发就是一对一了。
9.4 多对多
为什么要使用包装类?
1.建表
2.持久化类
3.mapper
<mapper namespace="com.itheima.mapper.OrderMapper">
<!-- 多对多嵌套查询:通过执行另外一条sql映射语句来返回预期的特殊类型-->
<select id="findOrdersWithProduct" parameterType="Integer"
resultMap="OrdersWithProductResult">
select *
from tb_orders where id = #{id}
</select>
<resultMap id="OrdersWithProductResult" type="com.itheima.po.Orders">
<id property="id" column="id"/>
<result property="number" column="number"/>
<collection property="productList" column="id" ofType="com.itheima.po.Product"
select="com.itheima.mapper.ProductMapper.findProductById"></collection>
</resultMap>
<!-- 多对多嵌套结果查询:查询某订单及其关联的商品详情-->
<select id="findOrdersWithProduct2" parameterType="integer"
resultMap="OrdersWithProductResult2">
select o.* , p.id as pid,p.name,p.price
from tb_orders o, tb_product p ,tb_ordersitem oi
where oi.orders_id = o.id
and oi.product_id = p.id
and o.id = #{id}
</select>
<resultMap id="OrdersWithProductResult2" type="com.itheima.po.Orders">
<id property="id" column="id" />
<result property="number" column="number"/>
<collection property="productList" ofType="com.itheima.po.Product">
<id property="id" column="pid" />
<result property="name" column="name"/>
<result property="price" column="price"/>
</collection>
</resultMap>
</mapper>
<mapper namespace="com.itheima.mapper.ProductMapper">
<select id="findProductById" parameterType="integer"
resultType="com.itheima.po.Product">
<!-- 查询订单id为#{id}的对应商品的商品信息-->
select *
from tb_product
where id in (
select product_id
from tb_ordersitem
where orders_id = #{id});
</select>
</mapper>
4.mybatis-config
<mappers>
<mapper resource="com/itheima/mapper/OrderMapper.xml"/>
<mapper resource="com/itheima/mapper/ProductMapper.xml"/>
</mappers>
5.测试类
【思考题】
1.请简述不同对象之间的三种关联关系。
一对一
一对多
多对多
2.请简述MyBatis关联查询映射的两种处理方式。
查询 一个sql语句穿插一个sql语句
结果 一个复杂sql语句完成
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术