Mybatis学习总结(六).Mybatis高级查询及延迟加载

来源:互联网 发布:sql镜像服务器 编辑:程序博客网 时间:2024/05/16 08:14

Mybatis作为一个ORM框架,也对SQL的高级查询做了支持,下面我们学习Mybatis下的一对一、一对多、多对多的查询。


案例说明:
此案例的业务关系是用户、订单、订单详情、商品之间的关系,其中,
一个订单只能属于一个人。
一个订单可以有多个订单详情。
一个订单详情中包含一个商品信息。
 
它们的关系是:
 
订单和人是 一对一的关系。
订单和订单详情是 一对多 的关系。

订单和商品是 多对多的关系。


数据库关系图:



一对一查询

需求:一对一查询:查询订单,并且查询出下单人的信息。

SQL:   SELECT  o.*, u.user_name,u. NAME FROM tb_order o LEFT JOIN tb_user u ON o.user_id = u.id WHERE order_number = '20140921001'

第一种实现:

User.java

package cn.zto.mybatis.pojo;import java.util.Date;/** *  * @ClassName:  User    * @Description:对应用户表 * @author: xyc  * @date:   2017年2月11日 下午8:11:13    * */public class User implements java.io.Serializable{        private static final long serialVersionUID = 1L;    private Long id;    // 用户名    private String userName;    // 密码    private String password;    // 姓名    private String name;    // 年龄    private Integer age;    // 性别,1男性,2女性    private Integer sex;    // 出生日期    private Date birthday;    // 创建时间    private Date created;    // 更新时间    private Date updated;    //getter And setter    @Override    public String toString() {        return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", name=" + name                + ", age=" + age + ", sex=" + sex + ", birthday=" + birthday + ", created=" + created                + ", updated=" + updated + "]";    }}

Order.java

package cn.zto.mybatis.pojo;/** *  * @ClassName:  Order    * @Description:对应订单表 * @author: xyc  * @date:   2017年2月11日 下午8:22:24    * */public class Order {    private Integer id;    private Long userId;    private String orderNumber;       //getter And setter    @Override    public String toString() {        return "Order [id=" + id + ", userId=" + userId + ", orderNumber=" + orderNumber + "]";    }}
OrderUser.java

package cn.zto.mybatis.pojo;/** *  * @ClassName:  OrderUser    * @Description: 此类用于补字段 * @author: xyc  * @date:   2017年2月11日 下午8:24:51    * */public class OrderUser extends Order{        private String userName;    private String name;       //getter and setter    @Override    public String toString() {        return "OrderUser [userName=" + userName + ", name=" + name + "]";    }}

OrderMapper.java

package cn.zto.mybatis.mapper;import cn.zto.mybatis.pojo.OrderUser;/** * 测试高级查询 */public interface OrderMapper {        /**     * 查询订单,并且查询出下单人的信息。     * @param orderNumber     * @return     */    public OrderUser queryOrderAndUserByOrderNumber(String orderNumber);    }

OrderMapper.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.zto.mybatis.mapper.OrderMapper"><select id="queryOrderAndUserByOrderNumber" resultType="OrderUser">SELECTo.*,u.user_name,  u.nameFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idWHERE order_number = #{orderNumber}</select></mapper>
记得加入到全局配置文件中:

测试结果:



第二种实现:

核心思想:面向对象的思想,在Order对象中添加User对象。


package cn.zto.mybatis.pojo;/** *  * @ClassName:  Order    * @Description:对应订单表 * @author: xyc  * @date:   2017年2月11日 下午8:33:12    * */public class Order {    private Integer id;    private Long userId;    private String orderNumber;        private User user;   //getter And setter}

Mapper接口:
/** * 查询订单,并且查询出下单人的信息。 * @param orderNumber * @return */ public Order queryOrderAndUserByOrderNumber2(String orderNumber);

Mapper映射文件
<!-- 在resultMap中,完成对象映射时,autoMapping默认为false,因此这里需要打开,否则有的属性关系无法对应 --><resultMap type="Order" id="orderResultMap" autoMapping="true"><id column="id" property="id"/><!-- 
association:用户映射java对象
property: 对象中的属性名称
javaType:对象中的属性的类型 --><association property="user" javaType="User" autoMapping="true"><id column="user_id" property="id"/></association></resultMap>

<!-- 使用resultType不能完成自动映射,所以需要手动完成结果集的映射,需要使用resultMap实现。-->

<select id="queryOrderAndUserByOrderNumber2" resultMap="orderResultMap">SELECTo.*,u.user_name, u.nameFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idWHERE order_number = #{orderNumber}</select>
测试:
@Testpublic void testQueryOrderAndUserByOrderNumber2() {    Order order = this.orderMapper.queryOrderAndUserByOrderNumber2("20140921001");    System.out.println(order);}
结果:



一对多查询

需求:查询订单,查询出下单人信息并且查询出订单详情。

SQL:
SELECTo.*,u.user_name,  u.name,od.id detail_id,od.item_id,od.total_priceFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idLEFT JOIN tb_orderdetail od ON o.id = od.order_idWHERE order_number = '20140921001'

Order.java
package cn.zto.mybatis.pojo;import java.util.List;/** * 订单表 *  */public class Order {    private Integer id;    private Long userId;    private String orderNumber;        private User user;        //映射一对多查询的订单详情    private List<Orderdetail> orderdetails;       //getter And setter        @Override    public String toString() {        return "Order [id=" + id + ", userId=" + userId + ", orderNumber=" + orderNumber + ", user=" + user                + ", orderdetails=" + orderdetails + "]";    }    }

Orderdetail.java
package cn.zto.mybatis.pojo;/** *  * @ClassName:  Orderdetail    * @Description:订单详情 * @author: xyc  * @date:   2017年2月11日 下午9:42:28    * */public class Orderdetail {        private Integer id;        private Double totalPrice;        private Integer status;        private Integer itemId;        private Item item;        //getter and setter}


接口:
/** * 查询订单,查询出下单人信息并且查询出订单详情。 *  * @param orderNumber * @return */public Order queryOrderAndUserAndOrderDetailByOrderNumber(String orderNumber);

Mapper映射文件:

<resultMap type="Order" id="orderUserOrderDetailresultMap" autoMapping="true"><id column="id" property="id"/><!-- association:映射java对象property: 对象中的属性名称javaType:对象中的属性的类型 --><association property="user" javaType="User" autoMapping="true"><id column="user_id" property="id"/></association><!-- collection:映射集合javaType: 属性的java类型ofType:集合中的对象的java类型 --><collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true"><id column="detail_id" property="id"/> </collection></resultMap><select id="queryOrderAndUserAndOrderDetailByOrderNumber" resultMap="orderUserOrderDetailresultMap">SELECTo.*,u.user_name,  u.name,od.id detail_id,od.item_id,od.total_priceFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idLEFT JOIN tb_orderdetail od ON o.id = od.order_idWHERE order_number = #{orderNumber}</select>

测试:
@Testpublic void testQueryOrderAndUserAndOrderDetailByOrderNumber() {    Order order = this.orderMapper.queryOrderAndUserAndOrderDetailByOrderNumber("20140921001");    System.out.println(order);}
结果:


多对多查询

需求:查询订单,查询出下单人信息并且查询出订单详情中的商品数据

SQL:
SELECTo.*,u.user_name,  u.name,od.id detail_id,od.item_id,od.total_price,i.item_name,i.item_price,i.item_detailFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idLEFT JOIN tb_orderdetail od ON o.id = od.order_idLEFT JOIN tb_item i ON od.item_id = i.idWHERE order_number  = '20140921001'

Item.java
package cn.zto.mybatis.pojo;/** * 商品表 */public class Item {    private Integer id;    private String itemName;    private Float itemPrice;    private String itemDetail;    //getter and setter}

Orderdetail.java
package cn.zto.mybatis.pojo;/** *  * @ClassName:  Orderdetail    * @Description:订单详情 * @author: xyc  * @date:   2017年2月11日 下午9:42:28    * */public class Orderdetail {        private Integer id;        private Double totalPrice;        private Integer status;        private Integer itemId;        private Item item;        //gette and setter }

接口:
/** * 多对多查询 * 查询订单,查询出下单人信息并且查询出订单详情中的商品数据。 * @param orderNumber * @return */public Order queryOrderAndUserAndOrderDetailAndItemByOrderNumber(String orderNumber);


Mapper映射:
<resultMap type="Order" id="orderUserOrderDetailItemResultMap"  autoMapping="true"><id column="id" property="id"/><!-- property: 对象中的属性名称javaType:对象中的属性的类型 --><association property="user" javaType="User" autoMapping="true"><id column="user_id" property="id"/></association><!-- 映射orderdetails --><collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true"><id property="id" column="detail_id"/><!-- 映射Orderdetail中的Item对象 --><association property="item" javaType="Item" autoMapping="true"><id property="id" column="item_id"/></association></collection></resultMap><select id="queryOrderAndUserAndOrderDetailAndItemByOrderNumber" resultMap="orderUserOrderDetailItemResultMap">SELECTo.*,u.user_name,  u.name,od.id detail_id,od.item_id,od.total_price,i.item_name,i.item_price,i.item_detailFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idLEFT JOIN tb_orderdetail od ON o.id = od.order_idLEFT JOIN tb_item i ON od.item_id = i.idWHERE order_number = #{orderNumber}</select>

测试:
@Testpublic void testQueryOrderAndUserAndOrderDetailAndItemByOrderNumber() {    Order order = this.orderMapper.queryOrderAndUserAndOrderDetailAndItemByOrderNumber("20140921001");    System.out.println(order);}

结果:


ResultMap的继承  

通过上述可以发现,下面代码重用了,如何解决呢?
<!-- 在resultMap中,完成对象映射时,autoMapping默认为false,因此这里需要打开,否则有的属性关系无法对应 --><resultMap type="Order" id="orderResultMap" autoMapping="true"><id column="id" property="id"/><!-- property: 对象中的属性名称javaType:对象中的属性的类型 --><association property="user" javaType="User" autoMapping="true"><id column="user_id" property="id"/></association></resultMap>

我们可以通过继承来完善
<resultMap type="Order" id="orderUserOrderDetailItemResultMap" extends="orderResultMap" autoMapping="true"><!-- 映射orderdetails --><collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true"><id property="id" column="detail_id"/><!-- 映射Orderdetail中的Item对象 --><association property="item" javaType="Item" autoMapping="true"><id property="id" column="item_id"/></association></collection></resultMap>

extends的值为上面resultMap的id.


延迟加载

延迟加载的意义在于,虽然是关联查询,但不是及时将关联的数据查询出来,而且在需要的时候进行查询


开启延迟加载:
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>


lazyLoadingEnabled:true使用延迟加载,false禁用延迟加载。默认为true
aggressiveLazyLoading:true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性)。默认为true


①. 添加cglib支持

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.1</version></dependency>


②.全局配置文件中开启延迟加载

<settings><!-- 开启驼峰映射 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 二级缓存的全局开关 --><setting name="cacheEnabled" value="true"/><!-- 延迟加载的开关 --><setting name="lazyLoadingEnabled" value="true"/><!-- true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性) --><setting name="aggressiveLazyLoading" value="false"/></settings>

③.编写接口:

/** * 测试延迟加载 * 查询订单,并且查询出下单人的信息。 * @param orderNumber * @return */public Order lazyQueryOrderAndUserByOrderNumber(String orderNumber);

④.编写Mapper.xml



⑤.测试:

@Testpublic void testLazyQueryOrderAndUserByOrderNumber() {    Order order = this.orderMapper.lazyQueryOrderAndUserByOrderNumber("20140921001");    User user = order.getUser();//触发延迟加载    System.out.println(user);    System.out.println(order);}

结果:




1 0
原创粉丝点击