MyBatis快速入门第六讲——一对一关联映射和一对多关联映射

在实际开发中我们不可能只是对单表进行操作,必然要操作多表。本文就来讲解多表操作中的一对一关联映射和一对多(或者多对一)关联映射,至于多对多关联映射实质上也是两个一对多(或者多对一)关联映射,所以在这里我并不打算讲解。那就先从一对一关联映射讲起吧!温馨提示:本文案例代码的编写是建立在前文《MyBatis快速入门第五讲——Mapper.xml文件中的输入和输出映射以及动态SQL》案例基础之上的!

一对一关联映射

这里,我会以商品订单数据模型为例来讲解一对一关联映射,商品订单数据模型如下图所示。
这里写图片描述

一对一查询

有这样一个需求:查询所有订单信息时,关联查询下单的用户信息。注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息角度出发关联查询用户信息,这是一对一查询(值得注意的一点是这儿我将订单与用户的关系理解为一对多的关系,但实质上从订单角度出发,多个订单应属于同一个用户,故订单与用户的关系应该是多对一的关系);如果从用户信息角度出发查询该用户下的订单信息则是一对多查询,因为一个用户可以下多个订单。解决该需求,一共有两种方法,先讲第一种方法。

方法一:使用resultType

使用resultType,定义一个订单信息po类,此po类中包括了订单信息和用户信息。于是,我们首先要在com.meimeixia.mybatis.pojo包下新建一个OrderUser类。

package com.meimeixia.mybatis.pojo;

/**
 * 订单关联用户信息的POJO
 * @author liayun
 *
 */
public class OrderUser extends Order {
	
	private String username;// 用户姓名
	private String address;// 地址
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "OrderUser [username=" + username + ", address=" + address + ", getId()=" + getId() + ", getUserId()="
				+ getUserId() + ", getNumber()=" + getNumber() + ", getCreatetime()=" + getCreatetime() + ", getNote()="
				+ getNote() + "]";
	}
	
}

OrderUser类继承Order类之后,自然就包括了Order类中的所有字段,所以在该类中只需要定义用户的信息字段即可。
然后,按照需求编写SQL语句,在OrderMapper.xml映射文件中添加一个如下<select>元素。

<!-- 一对一关联查询,resultType的使用,要想使用resultType,一定要与跟数据库关系一模一样的pojo -->
<select id="getOrderUser" resultType="orderuser">
	SELECT
		o.`id`,
		o.`user_id` userId,
		o.`number`,
		o.`createtime`,
		o.`note`,
		u.username,
		u.address 
	FROM
		`order` o
		LEFT JOIN `user` u ON u.id = o.user_id
</select>

接着,在OrderMapper接口中声明一个如下的方法。

/**
  * 一对一关联查询,resultType的使用
  * @return
  */
List<OrderUser> getOrderUser();

紧接着,在OrderMapperTest单元测试类中编写一个如下的测试方法。

@Test
public void testGetOrderUser() {
	SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
	//获取OrderMapper接口的代理实现类
	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
	List<OrderUser> list = orderMapper.getOrderUser();
	for (OrderUser orderUser : list) {
		System.out.println(orderUser);
	}
	sqlSession.close();
}

在以上方法中的for (OrderUser orderUser : list) {这句代码处打一个断点,继而以Debug模式运行该方法,大概就能看到你想要的结果了。

小结

定义专门的po类作为输出类型,其中定义了SQL查询结果集所有的字段。此方法较为简单,企业中使用普遍。

方法二:使用resultMap

使用resultMap,定义专门的resultMap用于映射一对一查询结果。首先要在Order类中加入一个User类型的user属性,该属性用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息。如此一来,Order类的代码就要改成下面这个样子了。

package com.meimeixia.mybatis.pojo;

import java.util.Date;

public class Order {
	private Integer id;

	private Integer userId;

	private String number;

	private Date createtime;

	private String note;
	
	private User user;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getUserId() {
		return userId;
	}

	public void setUserId(Integer userId) {
		this.userId = userId;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number == null ? null : number.trim();
	}

	public Date getCreatetime() {
		return createtime;
	}

	public void setCreatetime(Date createtime) {
		this.createtime = createtime;
	}

	public String getNote() {
		return note;
	}

	public void setNote(String note) {
		this.note = note == null ? null : note.trim();
	}
	
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Override
	public String toString() {
		return "Order [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
				+ ", note=" + note + "]";
	}

}

然后,在OrderMapper.xml映射文件中添加一个如下的<select>元素。

<select id="getOrderUserMap" resultMap="order_user_map">
	SELECT
		o.`id`,
		o.`user_id`,
		o.`number`,
		o.`createtime`,
		o.`note`,
		u.`username`,
		u.`address`,
		u.`birthday`,
		u.`sex`
	FROM
		`order` o
		LEFT JOIN `user` u ON u.id = o.user_id
</select>

上面id为order_user_map的resultMap也须定义,如下所示:

<!-- 定义resultMap -->
<resultMap type="order" id="order_user_map">
	<!-- <id>用于映射主键 -->
	<id property="id" column="id" />
	<!-- 普通字段用<result>来映射 -->
	<result property="userId" column="user_id" />
	<result property="number" column="number" />
	<result property="createtime" column="createtime" />
	<result property="note" column="note" />
	<!-- 
		<association>用于配置一对一关系 
			property:映射的是Order实体类里面的user属性
			javaType:Order实体类里面的user属性的数据类型,可以写成别名
	-->
	<association property="user" javaType="com.meimeixia.mybatis.pojo.User">
		<id property="id" column="user_id" />
		<result property="username" column="username" />
		<result property="address" column="address" />
		<result property="birthday" column="birthday" />
		<result property="sex" column="sex" />
	</association>
</resultMap>

针对以上<association>标签的配置,我觉得有必要说明如下几点:

  • association:该标签表示进行关联查询单条记录,即可以使用它来配置一对一关联关系。
    • property:该属性表示的是关联查询的结果要存储在Order实体类里面的user属性中。即它对应Order实体类里面一对一关联映射的那个属性(也就是user属性);
    • javaType:该属性表示的是关联查询的结果类型,即user属性的数据类型,可使用别名;
    • <id property="id" column="user_id"/>:意思是查询结果的user_id列对应关联对象的id属性,这儿的<id>标签表示user_id是关联查询对象的唯一标识;
    • <result property="username" column="username"/>:意思是查询结果的username列对应关联对象的username属性。

OrderMapper.xml映射文件配置好之后,我们还要在OrderMapper接口中声明一个如下方法。

/**
  * 一对一关联查询,resultMap的使用
  * @return
  */
List<Order> getOrderUserMap();

最后,在OrderMapperTest单元测试类中编写一个如下测试方法。

@Test
	public void testGetOrderUserMap() {
		SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
		//获取OrderMapper接口的代理实现类
		OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
		List<Order> list = orderMapper.getOrderUserMap();
		for (Order order : list) {
			System.out.println(order);
			System.out.println("     此订单的用户为:" + order.getUser());
		}
		sqlSession.close();
	}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述

小结

我们可以使用association标签完成关联查询,并将关联查询信息映射到pojo对象中。

一对多关联映射

现有这样一个需求:查询所有用户信息及用户所关联的订单信息。这儿,用户信息和订单信息为一对多关系。此处,我会使用resultMap来解决这个需求。首先在User实体类中加入一个List<Orders> orders属性,如此一来,User类的代码就要改成下面这个样子了。

package com.meimeixia.mybatis.pojo;

import java.util.Date;
import java.util.List;

public class User {

	private Integer id; // int类型的id是不可能为null的!
	private String username;// 用户姓名
	private String sex;// 性别
	private Date birthday;// 生日
	private String address;// 地址
	
	private String uuid2;
	
	private List<Order> orders;
	
	public List<Order> getOrders() {
		return orders;
	}

	public void setOrders(List<Order> orders) {
		this.orders = orders;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	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 getUuid2() {
		return uuid2;
	}

	public void setUuid2(String uuid2) {
		this.uuid2 = uuid2;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
				+ address + ", uuid2=" + uuid2 + "]";
	}

}

然后,在UserMapper.xml映射文件中添加一个如下的<select>元素。

<select id="getUserOrderMap" resultMap="user_order_map">
	SELECT
		u.`id`,
		u.`username`,
		u.`birthday`,
		u.`sex`,
		u.`address`,
		u.`uuid2`,
		o.`id` oid,
		o.`number`,
		o.`createtime`,
		o.`note`
	FROM
		`user` u
		LEFT JOIN `order` o ON o.`user_id` = u.`id`
</select>

上面id为user_order_map的resultMap也须定义,如下所示:

<!-- 定义resultMap -->
<resultMap type="user" id="user_order_map">
	<id property="id" column="id" />
	<result property="username" column="username" />
	<result property="address" column="address" />
	<result property="birthday" column="birthday" />
	<result property="sex" column="sex" />
	<!-- 
		<collection>用于配置一对多关联关系 
			property:映射的是User实体类里面的orders属性
			ofType:User实体类里面的orders属性的数据类型,可以写成别名
	-->
	<collection property="orders" ofType="order">
		<!-- <id>用于映射主键 -->
		<id property="id" column="oid" />
		<result property="userId" column="id" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
	</collection>
</resultMap>

针对以上<collection>标签的配置,我觉得有必要说明如下几点:

  • <collection>标签部分定义了用户关联的订单信息,即它表示关联查询结果集。
    • property:该属性表示关联查询的结果集存储在User对象的哪个属性上,也就是说它对应的是User对象中的集合属性;
    • ofType:该属性指定关联查询的结果集中的对象类型(即List集合中的元素类型)。此处可以使用别名,也可以使用全限定名;
    • <id>标签及<result>标签的意义同一对一查询。

UserMapper.xml映射文件配置好之后,我们还要在UserMapper接口中声明一个如下方法。

/**
  * 演示一对多的关联查询,使用resultMap
  * @return
  */
List<User> getUserOrderMap();

最后,在UserMapperTest单元测试类中编写一个如下测试方法。

@Test
public void testGetUserOrderMap() {
	SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
	//获取接口的代理实现类,只不过不需要我们去写了
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	List<User> list = userMapper.getUserOrderMap();
	for (User user : list) {
		System.out.println(user);
		for (Order order : user.getOrders()) {
			if (order.getId() != null) {
				System.out.println("         此用户下的订单有:" + order);
			}
		}
	}
	sqlSession.close();
}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
至此,一对一关联映射和一对多关联映射我就已经总结完了,觉得总结得还蛮走心的。

  • 13
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李阿昀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值