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

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">
		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 = #{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>

测试:




@Test
public void testQueryOrderAndUserByOrderNumber2() {
    Order order = this.orderMapper.queryOrderAndUserByOrderNumber2("20140921001");
    System.out.println(order);
}
结果:



一对多查询

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

SQL:
SELECT
			o.*,
			u.user_name,
		  u.name,
			od.id detail_id,
			od.item_id,
			od.total_price
		FROM
			tb_order o
		LEFT JOIN tb_user u ON o.user_id = u.id
		LEFT JOIN tb_orderdetail od ON o.id = od.order_id
		WHERE 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">
	SELECT
		o.*,
		u.user_name,
	  u.name,
		od.id detail_id,
		od.item_id,
		od.total_price
	FROM
		tb_order o
	LEFT JOIN tb_user u ON o.user_id = u.id
	LEFT JOIN tb_orderdetail od ON o.id = od.order_id
	WHERE order_number = #{orderNumber}
</select>

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


多对多查询

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

SQL:
SELECT
			o.*,
			u.user_name,
		  u.name,
			od.id detail_id,
			od.item_id,
			od.total_price,
			i.item_name,
			i.item_price,
			i.item_detail
		FROM
			tb_order o
		LEFT JOIN tb_user u ON o.user_id = u.id
		LEFT JOIN tb_orderdetail od ON o.id = od.order_id
		LEFT JOIN tb_item i ON od.item_id = i.id
		WHERE 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">
	SELECT
		o.*,
		u.user_name,
	  u.name,
		od.id detail_id,
		od.item_id,
		od.total_price,
		i.item_name,
		i.item_price,
		i.item_detail
	FROM
		tb_order o
	LEFT JOIN tb_user u ON o.user_id = u.id
	LEFT JOIN tb_orderdetail od ON o.id = od.order_id
	LEFT JOIN tb_item i ON od.item_id = i.id
	WHERE order_number = #{orderNumber}
</select>

测试:
@Test
public 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



⑤.测试:

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

结果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值