mybatis映射 一对一一对多多对多高级映射

Posted 猩猩之火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis映射 一对一一对多多对多高级映射相关的知识,希望对你有一定的参考价值。

1.数据库执行脚本

  创建数据库表代码:

技术分享
 
 1 CREATE TABLE items (
 2   id INT NOT NULL  AUTO_INCREMENT,
 3   itemsname VARCHAR(32) NOT NULL COMMENT 商品名称,
 4   price FLOAT(10,1) NOT NULL COMMENT 商品定价,
 5   detail TEXT COMMENT 商品描述,
 6   pic VARCHAR(64) DEFAULT NULL COMMENT 商品图片,
 7   createtime DATETIME NOT NULL COMMENT 生产日期,
 8   PRIMARY KEY (id)
 9 )  DEFAULT CHARSET=utf8;
10 
11 /*Table structure for table `orderdetail` */
12 
13 CREATE TABLE orderdetail (
14   id INT NOT NULL AUTO_INCREMENT,
15  orders_id INT NOT NULL COMMENT 订单id,
16   items_id INT NOT NULL COMMENT 商品id,
17   items_num INT  DEFAULT NULL COMMENT 商品购买数量,
18   PRIMARY KEY (id),
19   KEY `FK_orderdetail_1` (`orders_id`),
20   KEY `FK_orderdetail_2` (`items_id`),
21   CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
22   CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
23 )  DEFAULT CHARSET=utf8;
24 
25 /*Table structure for table `orders` */
26 
27 CREATE TABLE orders (
28   id INT NOT NULL AUTO_INCREMENT,
29   user_id INT NOT NULL COMMENT 下单用户id,
30   number VARCHAR(30) NOT NULL COMMENT 订单号,
31   createtime DATETIME NOT NULL COMMENT 创建订单时间,
32   note VARCHAR(100) DEFAULT NULL COMMENT 备注,
33   PRIMARY KEY (`id`),
34   KEY `FK_orders_1` (`user_id`),
35   CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
36 )  DEFAULT CHARSET=utf8;
37 
38 /*Table structure for table `t_user` */
39 
40 CREATE TABLE t_user (
41   id INT NOT NULL AUTO_INCREMENT,
42   username VARCHAR(32) NOT NULL COMMENT 用户名称,
43   birthday DATE DEFAULT NULL COMMENT 生日,
44   sex CHAR(1) DEFAULT NULL COMMENT 性别,
45   address  VARCHAR(256) DEFAULT NULL COMMENT 地址,
46   PRIMARY KEY (`id`)
47 ) DEFAULT CHARSET=utf8;
 
View Code

  测试数据代码:

 1 /*Data for the table `items` */
 2 
 3 INSERT  INTO items(itemsname,price,detail,pic,createtime) VALUES 
 4 (台式机,3000.0,该电脑质量非常好!,NULL,2015-07-07 13:28:53),
 5 (笔记本,6000.0,笔记本性能好,质量好!,NULL,2015-07-08 13:22:57),
 6 (背包,200.0,名牌背包,容量大质量好!,NULL,2015-07-010 13:25:02);
 7 
 8 /*Data for the table `orderdetail` */
 9 
10 INSERT  INTO `orderdetail`(`orders_id`,`items_id`,`items_num`) VALUES
11  (1,1,1),
12  (1,2,3),
13  (2,3,4),
14  (3,2,3);
15 
16 /*Data for the table `orders` */
17 
18 INSERT  INTO `orders`(`user_id`,`number`,`createtime`,`note`) VALUES 
19 (1,1000010,2015-06-04 13:22:35,NULL),
20 (1,1000011,2015-07-08 13:22:41,NULL),
21 (2,1000012,2015-07-17 14:13:23,NULL),
22 (3,1000012,2015-07-16 18:13:23,NULL),
23 (4,1000012,2015-07-15 19:13:23,NULL),
24 (5,1000012,2015-07-14 17:13:23,NULL),
25 (6,1000012,2015-07-13 16:13:23,NULL);
26 
27 /*Data for the table `user` */
28 
29 INSERT  INTO `t_user`(`username`,`birthday`,`sex`,`address`) VALUES 
30 (王五,NULL,2,NULL),
31 (张三,2014-07-10,1,北京市),
32 (张小明,NULL,1,河南郑州),
33 (陈小明,NULL,1,河南郑州),
34 (张三丰,NULL,1,河南郑州),
35 (陈小明,NULL,1,河南郑州),
36 (王五,NULL,NULL,NULL),
37  (小A,2015-06-27,2,北京),
38 (小B,2015-06-27,2,北京),
39 (小C,2015-06-27,1,北京),
40 (小D,2015-06-27,2,北京);
2.数据模型分析思路

(1).每张表记录的数据内容:分模块对每张表记录的内容进行熟悉,相当 于你学习系统 需求(功能)的过程;

(2).每张表重要的字段设置:非空字段、外键字段;

(3).数据库级别表与表之间的关系:外键关系;

(4).表与表之间的业务关系:在分析表与表之间的业务关系时一定要建立在某个业务意义基础上去分析

3.针对订单商品模型的数据库思路分析:

  用户表:t_user-->记录了购买商品的用户信息

  订单表:orders-->记录了用户所创建的订单(购买商品的订单)

  订单明细表:orderdetail-->记录了订单的详细信息即购买商品的信息

  商品表:items-->记录了商品信息

表与表之间的业务关系:

  在分析表与表之间的业务关系时需要建立 在某个业务意义基础上去分析。

  先分析数据级别之间有关系的表之间的业务关系:

t_userorders

  t_user---->orders:一个用户可以创建多个订单,一对多

  orders--->t_user:一个订单只由一个用户创建,一对一

orders和orderdetail

  orders--->orderdetail:一个订单可以包括多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系

  orderdetail--> orders:一个订单明细只能包括在一个订单中,一对一

orderdetail和itesm

  orderdetail--->itesms:一个订单明细只对应一个商品信息,一对一

  items--> orderdetail:一个商品可以包括在多个订单明细 ,一对多

再分析数据库级别没有关系的表之间是否有业务关系:

orders和items

  ordersitems之间可以通过orderdetail表建立 关系。

4.分析之后画出对应的图,方便直观的了解业务关系

技术分享

 

二、一对一查询

2.1.需求:查询订单信息,关联查询用户信息

2.2.resultType实现

2.2.1.sql语句   

    确定查询的主表:订单表,确定查询的关联表:用户表。

 
1 SELECT    t1.*,
2         t2.username,
3         t2.sex,
4         t2.address
5     FROM 
6         orders t1,
7         t_user t2
8 WHERE t1.user_id=t2.id
 

2.2.2.创建entity实体

  用户实体:User.java

package com.mybatis.entity;
import java.util.Date;
import java.util.List;
/** 
 * @ClassName: User
 * @Description: TODO(用户实体)
 * @author 阿赫瓦里
 */
public class User {
    private Integer id;
    // 姓名
    private String username;
    // 性别
    private String sex;
    // 地址
    private String address;
    // 生日
    private Date birthday;
    // 用户创建的订单列表
    private List<Orders> ordersList;
       // getter and setter ......
}

订单实体:orders.java

package com.mybatis.entity;
import java.util.Date;
import java.util.List;
/**
 * @ClassName: Orders
 * @Description: TODO(订单实体)
 * @author 阿赫瓦里
 */
public class Orders {
    /** 主键订单Id */
    private Integer id;
    /** 下单用户id */
    private Integer userid;
    /** 订单号 */
    private String number;
    /** 创建订单时间 */
    private Date createTime;
    /** 备注 */
    private String note;
    // 用户信息
    private User user;
    // 订单明细
    private List<OrderDetail> orderdetails;
       //  getter and setter ......
}

商品实体:Items.java

package com.mybatis.entity;
import java.util.Date;
/**
 * @ClassName: Items
 * @Description: TODO(商品实体类)
 * @author 阿赫瓦里
 */
public class Items {
    /** 商品表主键Id */
    private Integer id;
    /** 商品名称 */
    private String itemsName;
    /** 商品定价 */
    private float price;
    /** 商品描述 */
    private String detail;
    /** 商品图片 */
    private String picture;
    /** 生产日期 */
    private Date createTime;
// getter and setter ......
}

订单明细实体:OrderDetail.java

package com.mybatis.entity;
/**
 * @ClassName: OrderDetail
 * @Description: TODO(订单明细实体)
 * @author 阿赫瓦里
 */
public class OrderDetail {
    /** 主鍵,訂單明细表Id */
    private Integer id;
    /** 訂單Id */
    private Integer ordersId;
    /** 商品id */
    private Integer itemsId;
    /** 商品购买数量 */
    private Integer itemsNum;
    // 明细对应的商品信息
    private Items items;
        //  getter and setter ......
}

 创建一个包装类,将查询到的信息可以全部映射到此类:OrdersCustom.java

/**
 * @ClassName: OrdersCustom
 * @Description: TODO(订单的扩展类,通过此类映射订单和用户的查询结果,让此类继承字段较多的实体类)
 * @author: 阿赫瓦里
 */
public class OrdersCustom extends Orders {
    // 添加用户的属性
    private String username;
    private String sex;
    private String address;
        // getter and setter......
}

2.2.3.创建OrdersCustomMapper.java

package com.mybatis.Mapper;
import java.util.List;
import com.mybatis.entity.OrdersCustom;

/**
 * @ClassName: OrdersMapperCustom
 * @Description: TODO(OrdersMapperCustom的mapper)
 * @author 阿赫瓦里
 */
public interface OrdersCustomMapper {
    /** 查询订单,关联查询用户信息 */
    public List<OrdersCustom> findOrdersUser();
}

2.2.4.创建OrdersCustomMapper.xml和上面对应的接口名称一致,以便通过mapper接口加载配置文件

<?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">
<!-- namespace命名空间,作用就是对sql进行分类化的管理,理解为sql隔离
    注意:使用mapper代理开发时,namespace有特殊作用,namespace等于mapper接口地址
 -->
<mapper namespace="com.mybatis.mapper.OrdersCustomMapper">
        <!-- 查询订单,关联查询用户信息 -->
    <select id="findOrdersUser" resultType="com.mybatis.entity.OrdersCustom">
    SELECT t1.*,
        t2.username,
        t2.sex,
        t2.address
    FROM
        orders t1,
        t_user t2
    WHERE t1.user_id=t2.id
    </select>
</mapper>

2.3.resultMap实现

2.3.1. sql语句同上

2.3.2. resultMap映射思路:

    使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中(上面orders实体中已经添加)。

2.3.3 ordersCustomMapper.xml

   1. 定义resultMap

 1 <!-- 定义查询订单关联用户的 resultMap,将整个的查询结果映射到com.mybatis.entity.Orders中 -->
 2     <resultMap type="com.mybatis.entity.Orders" id="OrdersUserResultMap">
 3         <!-- 配置映射的订单信息 -->
 4         
 5         <!-- id:查询列中的唯一标识,订单信息中的唯一标识,如果多列组成唯一标识(如:一般数据库设计中的字典表 使用联合主键),就需要配置多个id 
 6             column:订单信息的唯一标识 列
 7             property:订单信息的唯一标识列所映射到orders中的那个属性(假如:数据库中orders表中的主键为orders_id,而实体属性名称为ordersId,
 8                 则这个配置应为<id column="orders_id" property="ordersId"/>,类似hibernate实体映射文件配置)。
 9         -->
10         <id column="id" property="id"/>
11         <result column="user_id" property="userid"/>
12         <result column="number" property="number"/>
13         <result column="createtime" property="createTime"/>
14         <result column="note" property="note"/>
15         
16         <!-- 配置映射的关联用户信息 -->
17         
18         <!--association:用于映射关联查询单个对象的信息
19             property:要将关联查询的用户信息映射到Orders中那个属性
20           -->
21         <association property="user" javaType="com.mybatis.entity.User">
22             <!-- id:关联查询用户的唯一标识 
23                 column:指定唯一标识用户信息的列
24                 property:映射到user的那个属性
25             -->
26             <id column="user_id" property="id"/>
27             <result column="username" property="username"/>
28             <result column="sex" property="sex"/>
29             <result column="address" property="address"/>
30         </association>
31         
32     </resultMap>

   2. statement定义

 1     <!-- 查询订单,关联查询用户信息,使用resultMap实现 -->
 2     <select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap">
 3             SELECT t1.*,
 4                 t2.username,
 5                 t2.sex,
 6                 t2.address
 7             FROM
 8                 orders t1,
 9                 t_user t2
10             WHERE t1.user_id=t2.id
11     </select>

 3.OrderCustomMapper.java接口中添加下面的方法

/** 查询订单关联查询用户信息,使用reslutMap实现*/
public List<Orders>findOrdersUserResultMap();

4.对是resultType和resultMap实现的Junit测试

 1 package com.mybatis.test;
 2 
 3 import java.io.InputStream;
 4 import java.util.List;
 5 
 6 import org.apache.ibatis.io.Resources;
 7 import org.apache.ibatis.session.SqlSession;
 8 import org.apache.ibatis.session.SqlSessionFactory;
 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
10 import org.junit.Before;
11 import org.junit.Test;
12 
13 import com.mybatis.entity.Orders;
14 import com.mybatis.entity.OrdersCustom;
15 import com.mybatis.mapper.OrdersCustomMapper;
16 
17 public class OrdersCustomMapperTest {
18 
19     private SqlSessionFactory sqlSessionFactory;
20 
21     // 此方法是在执行findUserByIdTest之前执行
22     @Before
23     public void setUp() throws Exception {
24         String resource = "SqlMapConfig.xml";
25         InputStream inputStream = Resources.getResourceAsStream(resource);
26         // 创建SqlSessionFcatory
27         sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
28     }
29 
30     // 查询订单,关联查询用户信息,使用resultType实现的测试
31     @Test
32     public void TestFindOrdersUser() {
33         SqlSession sqlSession = sqlSessionFactory.openSession();
34         // 创建代理对象
35         OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
36         // 调用mapper的方法
37         List<OrdersCustom> list = oc.findOrdersUser();
38         System.out.println(list);
39         sqlSession.close();
40     }
41 
42     // 查询订单,关联查询用户信息,使用resultMap实现的测试
43     @Test
44     public void TestFindOrdersUserResultMap() {
45         SqlSession sqlSession = sqlSessionFactory.openSession();
46         // 创建代理对象
47         OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
48         // 调用mapper的方法
49         List<Orders> list = oc.findOrdersUserResultMap();
50         System.out.println(list);
51         sqlSession.close();
52 
53     }
54 
55 }
5.resultTyperesultMap实现一对一查询小结

 实现一对一查询:

  a.resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。

  b.如果没有查询结果的特殊要求建议使用resultType

  c.resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。

  d.resultMap可以实现延迟加载,resultType无法实现延迟加载。

 

三、一对多查询

 3.1. 需求:查询订单(关联用户)及订单明细

 3.2. 在orders.java类中添加List<orderDetail> orderDetails属性(上面实体已添加)

    最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中.

3.3.在ordersCustomMapper.xml中添加如下代码

    <!-- 查询订单关联查询用户及订单明细 -->
    <select id="findOrdersAndOrderDetailResultMap" resultMap="ordersAndOrderDetailResultMap">
            SELECT 
                  t1.*,
                  t2.username,
                  t2.sex,
                  t2.address,
                  t3.id orderdetail_id,
                  t3.items_id,
                  t3.items_num,
                  t3.orders_id
            FROM
                  orders t1,
                  t_user t2,
                  orderdetail t3
            WHERE t1.user_id = t2.id AND t3.orders_id=t1.id
    </select>

resultMap的定义同样添加到ordersCustomMapper.xml

<!-- 查询订单(关联用户)及订单明细的resultMap -->
    <resultMap type="com.mybatis.entity.Orders" id="ordersAndOrderDetailResultMap" extends="OrdersUserResultMap">
        <!-- 订单信息 -->
        <!-- 关联用户信息 -->
        <!-- 使用extends继承,不用在中配置订单信息和用户信息的映射-->
        
        <!-- 关联订单明细信息 
            一个订单关联查询出了多条订单明细,要使用collection映射
            collection:对关联查询到的多条记录映射到集合中
            property:将关联查询到的多条记录映射到orders类的那个属性
            ofType:指定映射的集合属性中pojo的类型
        -->
        

以上是关于mybatis映射 一对一一对多多对多高级映射的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis之关联关系(一对多多对多)

Mybatis复杂映射开发:一对一一对多多对多查询

MyBatis --- 映射关系一对一对多多对多,懒加载机制

mybatis映射 一对一,一对多,多对多高级映射

Mybatis 高级映射,一对一,一对多,多对多映射

Mybatis学习总结——高级映射(一对一,一对多,多对多)