Mybatis学习笔记(3)—高级映射之一对一映射

2,428 阅读4分钟

MyBatis学习笔记(1)—使用篇

MyBatis学习笔记(2)—映射关系篇

MyBatis学习笔记(3)—高级映射之一对一映射

Mybatis学习笔记(4)-高级映射之一对多映射

Mybatis学习笔记(5)-高级映射之多对多映射

...敬请期待

上一节映射关系篇重点是阐述输入映射和输出映射,但是我们发现所有的查询都是基于单表的,所以这一节继续说多表查询,也就是我们所谓的高级映射,高级映射还是针对于输出映射的,又分为一对一、一对多、多对多。那么前面的数据库结构已经不够用了,所以我们这里重新建立一个订单商品数据模型,以该模型陆续讲解以上的各种映射。

数据库准备

在我们的数据库中,包含以下表:

顾客表(customers)

CREATE TABLE customers
(
  cust_id      int       NOT NULL AUTO_INCREMENT,
  cust_name    char(50)  NOT NULL ,
  cust_address char(50)  NULL ,
  cust_city    char(50)  NULL ,
  cust_state   char(5)   NULL ,
  cust_zip     char(10)  NULL ,
  cust_country char(50)  NULL ,
  cust_contact char(50)  NULL ,
  cust_email   char(255) NULL ,
  PRIMARY KEY (cust_id)
) ENGINE=InnoDB;

订单表(orders)

CREATE TABLE orders
(
  order_num  int      NOT NULL AUTO_INCREMENT,
  order_date datetime NOT NULL ,
  cust_id    int      NOT NULL ,
  PRIMARY KEY (order_num)
) ENGINE=InnoDB;

订单表包含cust_id,可以关联到customers表,表示下了该订单的客户

订单项(orderitems)

CREATE TABLE orderitems
(
  order_num  int          NOT NULL ,
  order_item int          NOT NULL ,
  prod_id    char(10)     NOT NULL ,
  quantity   int          NOT NULL ,
  item_price decimal(8,2) NOT NULL ,
  PRIMARY KEY (order_num, order_item)
) ENGINE=InnoDB;

订单项包含order_num,关联到orders表,记录该订单项属于哪一个订单。 prod_id表示该订单项是什么产品,关联到下面的products表。

商品(products)

CREATE TABLE products
(
  prod_id    char(10)      NOT NULL,
  vend_id    int           NOT NULL ,
  prod_name  char(255)     NOT NULL ,
  prod_price decimal(8,2)  NOT NULL ,
  prod_desc  text          NULL ,
  PRIMARY KEY(prod_id)
) ENGINE=InnoDB;

vend_id关联到下面的供应商表,表示该产品是哪家供应商生产的。

供应商

CREATE TABLE vendors
(
  vend_id      int      NOT NULL AUTO_INCREMENT,
  vend_name    char(50) NOT NULL ,
  vend_address char(50) NULL ,
  vend_city    char(50) NULL ,
  vend_state   char(5)  NULL ,
  vend_zip     char(10) NULL ,
  vend_country char(50) NULL ,
  PRIMARY KEY (vend_id)
) ENGINE=InnoDB;

有了以上这些表,我们来看看几种映射关系吧。

一对一映射

假设我们需要查询所有的订单信息,关联查询创建订单的顾客信息,因为一个订单只能有一个顾客,所以是一对一查询。根据前面的知识,我们可以使用resultType或者resultMap设置返回类型。

使用resultType进行一对一映射

查询语句:

SELECT o.order_num,o.order_date, c.*
    FROM orders AS o, customers AS c
    WHERE o.cust_id = c.cust_id

创建POJO,由于我们的查询结果包含两个表的内容,我们先定义Orders

public class Orders {
    private Integer orderNum;
    private Date orderDate;
    private Integer custId;
    //setter and getter
    ...
}

继承Orders自定义一个OrdersCustomers类,用于承载查询结果。

public class OrdersCustomers extends Orders {
    private String custName;
    private String custAddress;
    private String custCity;
    private String custState;
    private String custZip;
    private String custCountry;
    private String custContact;
    private String custEmail;
    //setter and getter
    ...
}

因为POJO中的属性都是驼峰式命名,数据库列名都是下划线式的,所以这里我们在mybatis的配置文件里设置上:

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true" />
</settings>

这样就可以实现数据库到POJO对象的自动映射了。

在Mapper中定义:

<select id="findOrdersCustomer" resultType="com.shuqing28.pojo.OrdersCustomers">
        SELECT o.order_num,o.order_date, c.*
        FROM orders AS o, customers AS c
        WHERE o.cust_id = c.cust_id
    </select>

DAO中定义好接口:

List<OrdersCustomers> findOrdersCustomer();

测试代码:

@Test
public void getOrdersCustomers(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
        List<OrdersCustomers> orders = ordersDao.findOrdersCustomer();
        System.out.println(orders);
    } finally {
        sqlSession.close();
    }
}

查询结果:

使用resultMap进行一对一映射

SQL语句不会变,我们首先在Orders中添加Customer属性:

private Customer customer;

定义resultMap:

<resultMap id="OrdersCustomerResultMap" type="com.shuqing28.pojo.Orders">
    <id column="order_num" property="orderNum"/>
    <result column="order_date" property="orderDate"/>
    <result column="cust_id" property="custId"/>
    
    <association property="customer" javaType="com.shuqing28.pojo.Customer">
        <id column="cust_id" property="custId"/>
        <result column="cust_name" property="custName"/>
        <result column="cust_address" property="custAddress"/>
        <result column="cust_city" property="custCity"/>
        <result column="cust_state" property="custState"/>
        <result column="cust_zip" property="custZip"/>
        <result column="cust_country" property="custCountry"/>
        <result column="cust_contact" property="custContact"/>
        <result column="cust_email" property="custEmail"/>
    </association>
</resultMap>

注意到使用association标签来配置映射关联的customer信息。该Map的id为OrdersCustomerResultMap,后面就可以使用了。

定义select语句:

 <select id="findOrdersCustomerMap" resultMap="OrdersCustomerResultMap">
    SELECT o.order_num,o.order_date, c.*
    FROM orders AS o, customers AS c
    WHERE o.cust_id = c.cust_id
</select>

我们使用上了前面定义的resultMap

定义接口

public List<Orders> findOrdersCustomerMap();

测试代码

@Test
public void getOrdersCustomersMap(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
        List<Orders> orders = ordersDao.findOrdersCustomerMap();
        System.out.println(orders);
    } finally {
        sqlSession.close();
    }
}

测试结果

总结:一对一映射,重点在于resultMap的association标签