mybatis的第七讲:高级输出映射
对于映射概念前面有说过,要是有忘记的麻烦回顾看下。
高级映射包括:一对一映射、一对多映射、多对多映射。那这个三种映射在mybatis中是如何实现的呢?
我这边有几个实体类:分别是用户、订单、商品、订单明细。那么如何分析出他们之间关系呢?
用户和订单关系:
用户到订单:一个用户可以创建多个订单 一对多关系
订单到用户:一个订单只能由一个用户创建一对一关系
订单和订单明细关系:
订单到订单明细:一个订单可以包括多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系
订单明细到订单:一个订单明细只能包括在一个订单中,一对一关系
订单明细和商品关系:
订单明细到商品:一个订单明细只对应一个商品信息,一对一关系
商品到订单明细:一个商品可以包括在多个订单明细,一对多关系
再分析数据库级别没有关系的表之间是否有业务关系:
orders和items:
orders和items之间可以通过orderdetail表建立关系。
分析实体之间关系是需要建立在一定业务基础上。
一对一查询:(两种实现方式resultType和resultMap)
需求:查询订单信息关联查询创建订单的用户信息
确定查询的主表:订单表
确定查询的关联表:用户表
关联查询使用内链接?还是外链接?
由于orders表中有一个外键(user_id),通过外键关联查询用户表只能查询出一条记录,可以使用内链接。
工程结构图:
下面就对这三种关系用mybatis来实现:
商品实体类:
package cn.mybatis.pojo;
import java.util.Date;
public class Items {
private Integer id;
private String name;
private Float price;
private String pic;
private Date createtime;
private String detail;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic == null ? null : pic.trim();
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail == null ? null : detail.trim();
}
@Override
public String toString() {
return "Items [id=" + id + ", name=" + name + ", price=" + price
+ ", pic=" + pic + ", createtime=" + createtime + ", detail="
+ detail + "]";
}
}
用户实体类:
package cn.mybatis.pojo;
import java.util.Date;
import java.util.List;
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
//用户和订单关系用户可以创建多个订单,一个订单只能有一个用户创建
private List<Orders> orderlist;
public List<Orders> getOrderlist() {
return orderlist;
}
public void setOrderlist(List<Orders> orderlist) {
this.orderlist = orderlist;
}
public int getId() {
return id;
}
public void setId(int 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;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
}
订单实体类:
package cn.mybatis.pojo;
import java.util.Date;
import java.util.List;
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//添加一个用户属性 一对一查询
private User user;
//添加一个订单明细 一对多查询
private List<Orderdetail> orderdetails;
public List<Orderdetail> getOrderdetails() {
return orderdetails;
}
public void setOrderdetails(List<Orderdetail> orderdetails) {
this.orderdetails = orderdetails;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.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;
}
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;
}
@Override
public String toString() {
return "Orders [id=" + id + ", userId=" + userId + ", number=" + number
+ ", createtime=" + createtime + ", note=" + note + ", user="
+ user + ", orderdetails=" + orderdetails + "]";
}
}
订单明细实体类:
package cn.mybatis.pojo;
public class Orderdetail {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
//明细对应的商品信息
private Items items;
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrdersId() {
return ordersId;
}
public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
}
public Integer getItemsId() {
return itemsId;
}
public void setItemsId(Integer itemsId) {
this.itemsId = itemsId;
}
public Integer getItemsNum() {
return itemsNum;
}
public void setItemsNum(Integer itemsNum) {
this.itemsNum = itemsNum;
}
/*public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}*/
@Override
public String toString() {
return "Orderdetail [id=" + id + ", ordersId=" + ordersId
+ ", itemsId=" + itemsId + ", itemsNum=" + itemsNum + "]";
}
}
订单包装类:
package cn.mybatis.pojo;
/**
* 订单的扩展类
* @author Hanson
* 通过此类可以映射订单和用户查询的结果,让此类继承包括字段较多的pojo类
*/
public class OrdersCustom extends Orders{
//添加用户的属性
private String username;
private String sex;
private String address;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "OrdersCustom [username=" + username + ", sex=" + sex
+ ", address=" + address + "]";
}
}
Mapper接口
package cn.mybatis.mapper;
import java.util.List;
import cn.mybatis.pojo.Orders;
import cn.mybatis.pojo.OrdersCustom;
import cn.mybatis.pojo.User;
/**
* 订单Mapper
* @author Hanson
*
*/
public interface OrdersCustomMapper {
/**
* 1,2代表一对一查询
* @return
* @throws Exception
*/
//1、查询订单关联用户信息
public List<OrdersCustom> findOrdersUser()throws Exception;
//2、查询订单关联用户信息
public List<Orders> findOrdersUserResultMap()throws Exception;
/**
* 一对多查询
* @return
* @throws Exception
*/
public List<Orders> findOrdersAndOrderdetailResultMap()throws Exception;
/**
* 多对多查询
* @return
* @throws Exception
*/
public List<User> findUserAndItemsResultMap()throws Exception;
}
Mapper.xml
<?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="cn.mybatis.mapper.OrdersCustomMapper">
<!-- 一对一查询 -->
<!-- 查询订单关联查询用户信息 -->
<select id="findOrdersUser" resultType="cn.mybatis.pojo.OrdersCustom">
SELECT
o.*,
u.`username`,
u.`birthday`,
u.`sex`,
u.`address`
FROM orders o, USER u
WHERE
o.`user_id`=u.`id`;
</select>
<select id="findOrdersUserResultMap" resultMap="OrdersResultMap">
SELECT
o.*,
u.`username`,
u.`birthday`,
u.`sex`,
u.`address`
FROM orders
o, USER u
WHERE o.`user_id`=u.`id`;
</select>
<!-- 定义一个ResultMap -->
<resultMap type="cn.mybatis.pojo.Orders" id="OrdersResultMap">
<!-- 配置映射的订单信息 -->
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 配置映射的关联的用户信息
association:用于映射关联查询单个对象信息
property:要将关联查询的用户信息映射到Oraders中哪一个属性
javaType:映射到Oraders属性的类型
-->
<association property="user" javaType="cn.mybatis.pojo.User">
<!-- 关联查询用户的唯一标识
column: 指定唯一标识用户信息的列
property:映射到User的哪个属性
-->
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="sex" property="sex" />
<result column="address" property="address" />
</association>
</resultMap>
<!-- 一对多查询 -->
<!-- 查询订单关联查询用户以及订单明细,使用resultMap -->
<select id="findOrdersAndOrderdetailResultMap" resultMap="OrdersAndOrderdetailResultMap">
SELECT
orders.*,
USER.`username`,
USER.`sex`,
USER.`address`,
orderdetail.`id`
orderdetail_id,
orderdetail.`items_id`,
orderdetail.`items_num`,
orderdetail.`orders_id`
FROM orders, USER ,orderdetail
WHERE
orders.`user_id`=user.`id`
AND orderdetail.`orders_id`=orders.`id`;
</select>
<!-- 查询订单关联查询用户以及订单明细 的resultMap
extends:使用继承,可以不用配置订单信息和用户信息
-->
<resultMap type="cn.mybatis.pojo.Orders" id="OrdersAndOrderdetailResultMap"
extends="OrdersResultMap">
<!-- 订单信息,用户信息 -->
<!-- 使用了继承便可以省略 -->
<!-- 订单明细信息 一个订单关联多个订单明细信息,要使用collection进行映射
collection:对关联查询到的多条纪录映射到集合对象中
ofType:指定映射到ordes中的list集合属性中pojo的类型
-->
<collection property="orderdetails" ofType="cn.mybatis.pojo.Orderdetail">
<id column="orderdetail_id" property="id" />
<result column="orders_id" property="ordersId" />
<result column="items_id" property="itemsId" />
<result column="items_num" property="itemsNum" />
</collection>
</resultMap>
<!-- 多对多查询 -->
<!-- 查询用户及购买商品的详情,使用resultMap -->
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
SELECT
orders.*,
USER.`username`,
USER.`sex`,
USER.`address`,
orderdetail.`id` orderdetail_id,
orderdetail.`items_id`,
orderdetail.`items_num`,
orderdetail.`orders_id`,
items.`name` items_name,
items.`detail` items_detail,
items.`price` items_price
FROM orders, USER ,orderdetail,items
WHERE orders.`user_id`=user.`id`
AND orderdetail.`orders_id`=orders.`id`
AND orderdetail.`items_id`=items.`id`;
</select>
<!-- 查询用户及购买商品的详情的resultMap -->
<resultMap type="cn.mybatis.pojo.User" id="UserAndItemsResultMap">
<!-- 用户信息 -->
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="sex" property="sex" />
<result column="address" property="address" />
<!-- 订单信息 ,一个用户对应多个订单 -->
<collection property="orderlist" ofType="cn.mybatis.pojo.Orders">
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 订单详情,一个订单 多个订单详情 -->
<collection property="orderdetails" ofType="cn.mybatis.pojo.Orderdetail">
<id column="orderdetail_id" property="id" />
<result column="items_id" property="itemsId" />
<result column="items_num" property="itemsNum" />
<result column="orders_id" property="ordersId" />
<!-- 商品信息,一个订单详情,对应一个商品 -->
<association property="items" javaType="cn.mybatis.pojo.Items">
<id column="items_id" property="id" />
<result column="items_name" property="name" />
<result column="items_detail" property="detail" />
<result column="items_price" property="price" />
</association>
</collection>
</collection>
</resultMap>
</mapper>
一对一关系测试:
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import cn.mybatis.mapper.OrdersCustomMapper;
import cn.mybatis.pojo.Orders;
import cn.mybatis.pojo.OrdersCustom;
public class OrdersCustomMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources//
.getResourceAsStream("MyBatisConfig.xml"));
}
@After
public void tearDown() throws Exception {
}
@Test
public void testFindOrdersUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersCustomMapper ordersCustomMapper =sqlSession.getMapper(OrdersCustomMapper.class);
List<OrdersCustom> list = ordersCustomMapper.findOrdersUser();
for (OrdersCustom ordersCustom : list) {
System.out.println(ordersCustom);
}
sqlSession.close();
}
@Test
public void testFindOrdersUserResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersCustomMapper ordersCustomMapper =sqlSession.getMapper(OrdersCustomMapper.class);
List<Orders> list = ordersCustomMapper.findOrdersUserResultMap();
System.out.println(list);
sqlSession.close();
}
}
一对多关系测试:
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import cn.mybatis.mapper.OrdersCustomMapper;
import cn.mybatis.pojo.Orders;
public class OrdersCustomMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources//
.getResourceAsStream("MyBatisConfig.xml"));
}
@After
public void tearDown() throws Exception {
}
@Test
public void testFindOrdersAndOrderdetailResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersCustomMapper ordersCustomMapper =sqlSession.getMapper(OrdersCustomMapper.class);
List<Orders> list =ordersCustomMapper.findOrdersAndOrderdetailResultMap();
System.out.println(list.size());
}
}
多对多关系测试:
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import cn.mybatis.mapper.OrdersCustomMapper;
import cn.mybatis.pojo.User;
public class OrdersCustomMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources//
.getResourceAsStream("MyBatisConfig.xml"));
}
@After
public void tearDown() throws Exception {
}
@Test
public void testFindUserAndItemsResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersCustomMapper ordersCustomMapper =sqlSession.getMapper(OrdersCustomMapper.class);
List<User> list =ordersCustomMapper.findUserAndItemsResultMap();
System.out.println(list.size());
}
}
resultMap和resultType使用小结实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。
resultMap可以实现延迟加载,resultType无法实现延迟加载。
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
使用resultType实现:
将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。
多对多查询总结
将查询用户购买的商品信息明细清单,(用户名、用户地址、购买商品名称、购买商品时间、购买商品数量)
针对上边的需求就使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能。
一对多是多对多的特例,如下需求:
查询用户购买的商品信息,用户和商品的关系是多对多关系。
需求1:
查询字段:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)
企业开发中常见明细列表,用户购买商品明细列表,
使用resultType将上边查询列映射到pojo输出。
需求2:
查询字段:用户账号、用户名称、购买商品数量、商品明细(鼠标移上显示明细)
使用resultMap将用户购买的商品明细列表映射到user对象中。
总结:
使用resultMap是针对那些对查询结果映射有特殊要求的功能,,比如特殊要求映射成list中包括多个list。
ResultMap总结
resultType:
作用:
将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:
常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。
resultMap:
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
作用:
将关联查询信息映射到一个pojo对象中。
场合:
为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。
使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
collection:
作用:
将关联查询信息映射到一个list集合中。
场合:
为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
如果使用resultType无法将查询结果映射到list集合中。 本文为慕课网作者原创,转载请标明【原文作者及本文链接地址】。侵权必究,谢谢合作!
热门评论
http://blog.csdn.net/ykzhen2015/article/details/51161141
还是不如我那级联五篇讲得好,N+1问题,延迟加载都没有讲,看来我需要开课挣钱了。O(∩_∩)O
问下楼主,这些关联映射,与数据库中建不建外键关联关系 ,有联系吗? 一直不用外键关联好多年了。。。
大神,能不能把源码包+数据库脚本上传一下,感激不尽!