09. MyBatis的关系映射

1. 关联关系概述

在关系型数据库中,多表之间存在着三种关联关系,分别为一对一、一对多和多对多

在这里插入图片描述

关系说明
一对一在任意一方引入对方主键作为外键
一对多在“多”的一方,添加“一”的一方的主键作为外键
多对多产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键

在Java中,通过对象也可以进行关系描述

在这里插入图片描述

关系说明
一对一的关系就是在本类中定义对方类型的对象,如A类中定义B类类型的属性b, B类中定义A类类型的属性a
一对多的关系就是一个A类类型对应多个B类类型的情况,需要在A类中以集合的方式引入B类类型的对象,在B类中定义A类类型的属性a
多对多的关系在A类中定义B类类型的集合,在B类中定义A类类型的集合

2. 一对一关系

在现实生活中,一对一关联关系是十分常见的。例如,一个人只能有一个身份证,同时一个身份证也只会对应一个人。
在这里插入图片描述

07. MyBatis的核心配置所讲解的< resultMap>元素中,包含了一个< association>子元素,MyBatis就是通过该元素来处理一对一关联关系的。
在< association>元素中的属性

属性作用
property指定映射到的实体类对象属性,与表字段一一对应
column指定表中对应的字段
javaType指定映射到实体对象属性的类型
select定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询
1.两种使用方式
		<!-- 方式1:嵌套查询 -->
		<association property="card" column="card_id"
			javaType="IdCard" 
			select="com.clarence.mapper.IdCardMapper.findCodeById">
		</association>
		<!-- 方式2:嵌套结果 -->
		<association property="card"
			javaType="com.clarence.po.IdCard" >
			<id property="id" column="card_id"></id>
			<result property="code" column="code" />
		</association>

1.嵌套查询
示例代码

1.持久化类
public class IdCard {
    private Integer id;
    private String code;
    //省略getter和setter
}
public class Person {
    private Integer id;
    private String name;
    private String age;
    private String sex;
    private IdCard Card;
    //省略getter和setter
}
2.IdCardMapper.xml文件配置
<mapper namespace="com.clarence.mapper.IdCardMapper">
	<select id="findCodeById" parameterType="Integer"
		resultType="IdCard">
		SELECT * from tb_idcard where id=#{id}
	</select>
</mapper>
3.PersonMapper.xml文件配置
<mapper namespace="com.clarence.mapper.PersonMapper">
	<select id="findPersonById" parameterType="Integer"
		resultMap="IdCardWithPersonResult">
		select * from tb_person where id=#{id}
	</select>
		<resultMap type="Person" id="IdCardWithPersonResult">
		<id property="id" column="id" />
		<result property="name" column="name" />
		<result property="age" column="age" />
		<result property="sex" column="sex" />
		<!-- 方式1:嵌套查询 -->
		<!-- 一对一关系:association使用select属性引入另一条SQL -->
 		<association property="card" column="card_id"
			javaType="IdCard" 
			select="com.clarence.mapper.IdCardMapper.findCodeById">
		</association>
	</resultMap>	
</mapper>
4.MyBatis-config.xml配置无特别变化,只需引入两个mapper
5.测试类
    @Test
    public void findPersonByIdTest() {
        // 1.生产SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 2.嵌套查询id为1的人的信息
        Person person = sqlSession.selectOne(
                "com.clarence.mapper.PersonMapper.findPersonById", 1);
        System.out.println(person);
        sqlSession.close();
    }

运行结果
在这里插入图片描述
2.嵌套结果

1.只需更改PersonMapper的查询语句和映射结果
1.1 sql改写
select p.*,idcard.code from tb_person p,tb_idcard idcard
           where p.card_id = idcard.id and p.id= #{id}
1.2 association改写
<association property="card"
            javaType="IdCard" >
            <id property="id" column="card_id"></id>
            <result property="code" column="code" />
        </association>

运行结果
在这里插入图片描述

在使用MyBatis嵌套查询方式进行MyBatis关联查询映射时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件mybatis-config.xml中的< settings>元素内进行配置

	<settings>
		<!-- 打开延迟加载 -->
		<setting name="lazyLoadingEnabled" value="true" />
		<!-- 将积极加载改为消息加载,即按需加载 -->
		<setting name="aggressiveLazyLoading" value="false" />
	</settings>

在映射文件中,MyBatis关联映射的< association>元素和< collection>元素中都已默认配置了延迟加载属性,即默认属性fetchType=“lazy”(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无须在映射文件中再做配置

3. 一对多关系

与一对一的关联关系相比,开发人员接触更多的关联关系是一对多(或多对一)
例如一个用户可以有多个订单,同时多个订单归一个用户所有
在这里插入图片描述
07. MyBatis的核心配置所讲解的< resultMap>元素中,包含了一个< collection>子元素,MyBatis就是通过该元素来处理一对多关联关系的。< collection>子元素的属性大部分与< association>元素相同,但其还包含一个特殊属性——ofType。ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型

示例代码

1.持久化类
public class User {
    private Integer id;
    private String username;
    private String address;
    private List<Orders> ordersList;
    }
public class Orders {
	private Integer id;
	private String number;
	}    
2.UserMapper.xml配置
<mapper namespace="com.clarence.mapper.UserMapper">
	<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 type="User" id="UserWithOrdersResult">
		  <id property="id" column="id"/>
		  <result property="username" column="username"/>
		  <result property="address" column="address"/>
		  <!-- 一对多关系 
		      ofType 表示属性集合中元素的类型,List<Orders>属性即Orders类
		  -->
		  <collection property="ordersList" ofType="Orders">
		      <id property="id" column="orders_id"/>
		      <result property="number" column="number"/>
		  </collection>		  
		</resultMap>
</mapper>
3.测试类
    @Test
    public void findUserTest() {
        // 1.生产SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 2.嵌套查询id为1的用户信息
        User user = sqlSession.selectOne(
                "com.clarence.mapper.UserMapper.findUserWithOrders", 1);
        System.out.println(user);
        sqlSession.close();
    }

运行结果
在这里插入图片描述

4. 多对多关系

在实际项目开发中,多对多的关联关系也是非常常见的。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多个订单,订单和商品就属于多对多的关联关系
在这里插入图片描述
在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id
在这里插入图片描述
示例代码

1.持久化类
public class Product {
    private Integer id;
    private String name;
    private Double price;
    private List<Orders> orders;
    }
Orders类中添加
    private List<Product> productList;
2.OrderMapper.xml文件配置
<mapper namespace="com.clarence.mapper.OrdersMapper">
	<!-- 多对多嵌套查询 -->
	<select id="findOrderWithProduct" parameterType="Integer"
		resultMap="OrdersWithProductResult">
		select * from tb_orders where id=#{id}
	</select>

	<resultMap type="Orders" id="OrdersWithProductResult">
		<id property="id" column="id" />
		<result property="number" column="number" />
		<collection property="productList" column="id"
			ofType="Product"
			select="com.clarence.mapper.ProductMapper.findProductById">
		</collection>
	</resultMap>
</mapper>
3.ProductMapper.xml文件配置
<mapper namespace="com.clarence.mapper.OrdersMapper">
	<!-- 多对多嵌套查询 -->
	<select id="findOrderWithProduct" parameterType="Integer"
		resultMap="OrdersWithProductResult">
		select * from tb_orders where id=#{id}
	</select>

	<resultMap type="Orders" id="OrdersWithProductResult">
		<id property="id" column="id" />
		<result property="number" column="number" />
		<collection property="productList" column="id"
			ofType="Product"
			select="com.clarence.mapper.ProductMapper.findProductById">
		</collection>
	</resultMap>
</mapper>
4. 测试类
   @Test
    public void findOrdersTest() {
        // 1.生产SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 2.嵌套查询id为1的用户信息
        Orders orders = sqlSession.selectOne(
                "com.clarence.mapper.OrdersMapper.findOrderWithProduct", 1);
        System.out.println(orders);
        sqlSession.close();
    }

运行结果
在这里插入图片描述
当然多对多也可以使用嵌套结果方式 ~,但我不熟练嵌套查询语句 ~,所以就放弃了 ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值