继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

MyBatis3.2.x从入门到精通之第七章

HansonQ
关注TA
已关注
手记 21
粉丝 334
获赞 3452

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集合中。
本文为慕课网作者原创,转载请标明【原文作者及本文链接地址】。侵权必究,谢谢合作!
打开App,阅读手记
22人推荐
发表评论
随时随地看视频慕课网APP

热门评论

http://blog.csdn.net/ykzhen2015/article/details/51161141

还是不如我那级联五篇讲得好,N+1问题,延迟加载都没有讲,看来我需要开课挣钱了。O(∩_∩)O

问下楼主,这些关联映射,与数据库中建不建外键关联关系 ,有联系吗? 一直不用外键关联好多年了。。。

大神,能不能把源码包+数据库脚本上传一下,感激不尽!

查看全部评论