02-2-高级查询
第一章 动态SQLTODO
1.动态标签介绍
MyBatis 的强大特性之一便是**它的动态 SQL**。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。<br />场景:<br />【需求】:查询**男性**用户,**如果输入了用户名,按用户名模糊查询**,如果**没有输入用户名,就查询所有男性用户**。<br /><br /> 在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 开始精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的 OGNL 的表达式来淘汰其它大部分元素。
了解:OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。
动态SQL中的业务逻辑判断需要使用到以下运算符: ognl表达式
1. e1 or e2 满足一个即可2. e1 and e2 都得满足3. e1 == e2,e1 eq e2 判断是否相等4. e1 != e2,e1 neq e2 不相等5. e1 lt e2:小于 lt表示less than6. e1 lte e2:小于等于,其他gt(大于),gte(大于等于) gt 表示greater than7. e1 in e28. e1 not in e29. e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e210. !e,not e:非,求反11. e.method(args)调用对象方法12. e.property对象属性值 user.userName13. e1[ e2 ]按索引取值,List,数组和Map14. @class@method(args)调用类的静态方法15. @class@field调用类的静态字段值
常见标签如下:
if:判断 if(1 gt 2){}choose (when, otherwise):分支判断 switch:多选一where标签set标签foreach:循环遍历标签
2.if标签
语法格式:
<if test="判断条件">满足条件sql加入拼接</if>说明:1)if标签:判断语句,用于进行逻辑判断的。如果判断条件为true,则执行if标签的文本内容2)test属性:用来编写表达式,支持ognl;
【需求】:查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用
要求:
1.使用
2.test属性:使用OGNL表达式,完成具体的判断业务逻辑;
1)定义接口
/*** 【需求】:查询男性用户,如果输入了用户名,* 按用户名模糊查询,如果没有输入用户名,就查询所有男性用*/List<User> findUsersByUserName(@Param("userName") String userName);
2)定义接口方法对应的映射文件信息
<select id="findUsersByUserName" resultMap="userMap">select * from user where sex='男'<if test="userName!=null">and user_name like concat('%',#{userName},'%')</if></select>
3)测试方法
@Testpublic void test22(){UserMapper mapper = MybatisUtil.getMapper(UserMapper.class);//select * from user where sex='男'//List<User> users = mapper.findUsersByUserName(null);//select * from user where sex='男' and concat('%',?,'%');List<User> users = mapper.findUsersByUserName("唐僧");System.out.println(users);MybatisUtil.close();}
4)效果:
小结:
if标签使用方式?
<!--如果条件满足,则if标签包裹的sql会参与拼接,否则忽略--><if test="条件表达式">sql代码</if>
3.choose,when,otherwise
choose标签:分支选择(多选一,遇到成立的条件即停止)when子标签:编写条件,不管有多少个when条件,一旦其中一个条件成立,后面的when条件都不执行。test属性:编写ognl表达式otherwise子标签:当所有条件都不满足时,才会执行该条件。
语句示例:
<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose></select>
需求:
编写一个查询方法,设置两个参数,一个是用户名,一个是住址。根据用户名或者住址查询所有男性用户:如果输入了用户名则按照用户名模糊查找,否则就按照住址查找,两个条件只能成立一个,如果都不输入就查找用户名为“孙悟空”的用户。username address
【需求分析】
-- 输入了用户名select * from user where sex='男' and user_name like '%参数%'-- 没有输入姓名,但是输入了地址select * from user where sex='男' and address = '参数'-- 什么也没输入select * from user where sex='男' and user_name = '孙悟空'
1)定义接口方法
List<User> findUsersByNameAndAddress(@Param("name") String userName,@Param("address") String address);
2)定义接口方法对应的映射文件信息
<select id="findUsersByNameAndAddress" resultMap="userMap">select * from user where sex='男'<choose><when test="name!=null">and user_name like concat('%',#{name},'%')</when><when test="address!=null">and address=#{address}</when><otherwise>and user_name='孙悟空'</otherwise></choose></select>
3)测试
@Testpublic void test23(){UserMapper mapper = MybatisUtil.getMapper(UserMapper.class);//select * from user where sex='男' and user_name like concat('%',?,'%')//List<User> users = mapper.findUsersByNameAndAddress("唐僧", "花果山水帘洞");//select * from user where sex='男' and address=?//List<User> users = mapper.findUsersByNameAndAddress(null, "花果山水帘洞");//select * from user where sex='男' and user_name='孙悟空'List<User> users = mapper.findUsersByNameAndAddress(null, null);System.out.println(users);MybatisUtil.close();}
小结:
多选一使用方式?
规则:多选一,自上而下执行,遇到满足条件就退出,否则otherwise下的语句参与拼接<choose><when test="条件">sql代码</when><when test="条件">sql代码</when>....<otherwise>sql代码</otherwise></choose>
4.where
where标签:拼接多条件查询时 1、能够添加where关键字; 2、能够去除多余的and或者or关键字
需求:按照如下条件查询所有用户
如果只输入了用户名按照用户名进行查询;select * from user where user_name like concat('%',#{userName},'%');如果只输入住址,按住址进行查询;select * from user where address=#{address};如果两者都输入,则按照两个条件查询;select * from user where user_name like concat('%',#{userName},'%') and address=#{address};如果两者都不合符条件,全表查询;select * from user
where多条件语法格式:
<select/update/delete ...>sql语句<where><if test="条件">字段 = #{值}</if><if test="条件">AND 字段名 = #{值}</if></where></select/update/delete/insert>
1)定义接口
List<User> findByNameAndAddress(@Param("name") String name,@Param("address") String address);
2)定义xml
<!--where标签作用:1)适当添加where关键字2)被where标签包裹的sql会自动去除多余的and或者or关键字--><select id="findByNameAndAddress" resultMap="userMap">select * from user<where><if test="name!=null">user_name like concat('%',#{name},'%')</if><if test="address!=null">and address=#{address}</if></where></select>
3)测试
@Testpublic void test24(){UserMapper mapper = MybatisUtil.getMapper(UserMapper.class);//select * from user where user_name like concat('%',?,'%')//List<User> users = mapper.findByNameAndAddress("唐僧", null);//select * from user where address=?//List<User> users = mapper.findByNameAndAddress(null, "长安");//select * from user//List<User> users = mapper.findByNameAndAddress(null, null);//select * from user user_name like concat('%',?,'%') and address=?List<User> users = mapper.findByNameAndAddress("唐僧", "花果山水帘洞");System.out.println(users);MybatisUtil.close();}
小结:
通过使用
作用:1)适当添加where关键字2)去除被where标签包裹的多余的and或者or关键字语法格式:<where><if test="条件1">and sql1</if><if test="条件2">and sql2</if></where>
5.set
set标签:在update语句中,可以自动添加一个set关键字,并且会将动态sql最后多余的逗号去除。
语法格式:
<update .......>update 表名<set><if test='条件'>字段名1=值1,</if><if test='条件2'>字段名2=值2,</if>....</set>where 条件;</update>
案例:修改用户信息,如果参数user中的某个属性为null,则不修改。
1)定义接口方法
/*** 案例:修改用户信息,如果参数user中的某个属性为null,则不修改。* @param user*/void updateSelectiveUser(User user);
2)定义映射文件
<update id="updateSelectiveUser">update user<set><if test="username!=null">user_name=#{username},</if><if test="birthday!=null">birthday=#{birthday},</if><if test="sex!=null">sex=#{sex},</if><if test="address!=null">address=#{address}</if></set>where id=#{id}</update>
3)测试
@Testpublic void test25(){UserMapper mapper = MybatisUtil.getMapper(UserMapper.class);User user = new User();user.setUsername("沙悟净");user.setId(2);user.setSex("男");//update user set user_name=?,sex=? where id=?mapper.updateSelectiveUser(user);MybatisUtil.commit();MybatisUtil.close();}

小结:
set标签的作用?
1)去除被set标签包裹的多余的逗号','2)添加set关键字;
6.foreach
foreach标签:遍历集合或者数组<foreach collection="集合名或者数组名" item="元素" separator="标签分隔符" open="以什么开始" close="以什么结束">#{元素}</foreach>collection属性:接收的集合或者数组,集合名或者数组名item属性:集合或者数组参数中的每一个元素separator属性:标签分隔符open属性:以什么开始close属性:以什么结束举例:java接口方法:List<Post> selectPostIn(@Param("ids") List<Integer> ids);sql映射文件配置:<select id="selectPostIn" resultType="domain.blog.Post">SELECT * FROM POST PWHERE ID in<foreach collection="ids" item="item" open="(" separator="," close=")">#{item}</foreach></select>
需求:按照id值是1,2,3来查询(删除)用户数据;
1)定义接口
List<User> findByIds(@Param("ids") List<Integer> ids);
2)定义xml映射
<!--collection="ids":表示接口中传入的集合名称item="item":表示循环集合过程中的每一个元素separator=",":表示元素与元素拼接时的分隔符open="(" :表示拼接字符串时以指定字符开头close=")":表示拼接字符串时以指定字符结尾拼接格式:(1,3,6,8)--><select id="findByIds" resultMap="userMap">select * from user where id in<foreach collection="ids" item="item" separator="," open="(" close=")">#{item}</foreach></select>
3)测试
@Testpublic void test21(){UserMapper mapper = MybatisUtils.getMapper(UserMapper.class);//List<Integer> integers = Arrays.asList(1, 3, 5, 7, 9);//select * from user where id in(?,?,?,?,?)List<User> users = mapper.findByIds(Arrays.asList(1, 3, 5, 7));System.out.println(users);MybatisUtils.close();}
4)效果
小结:
foreach标签属性作用?
作用:遍历从接口中出入的集合的;语法格式:<foreach collection="接口中集合名称" item="集合中每一个元素" open="拼接以指定字符开头" close="拼接以指定字符结尾" separator="指定间隔符">#{集合中每一个元素}</forech>
6.动态sql总结
核心的动态sql标签有哪些,各有什么作用?
1)if标签<if test="条件">sql语句(如果满足条件,当前sql片段参与拼接)</if>2)choose when otherwise多选一 自上而下执行,遇到满足条件则退出,否则otherwise小的sql参与拼接<choose><when test="条件1">sql语句(如果满足条件,就参与sql拼接)</when><when test="条件1">sql语句(如果满足条件,就参与sql拼接)</when><otherwise>sql语句</otherwise></choose>3)where作用:1)适当添加where关键字 2)去除多余and或者or关键字4)set作用:1)添加set关键字 2)去除多余的逗号5)foreach标签:作用:遍历从接口中出入的集合的;语法格式:<foreach collection="接口中集合名称" item="集合中每一个元素" open="拼接以指定字符开头" close="拼接以指定字符结尾" separator="指定间隔符">#{集合中每一个元素}</forech>
第二章 特殊字符处理
我们在编写Mapper映射文件时,有时候需要使用到一些诸如:`>`,`<`之类的特殊字符。这些字符不能直接书写在xml文件中,需要我们对其处理。<br /> 处理方式:使用转义字符代替特殊字符。
| 转义字符 | sql符号 | 说明 |
|---|---|---|
| < | < | 小于 |
| > | > | 大于 |
| & | & | 和号 |
| ' | ‘ | 单引号 |
| " | “ | 双引号 |
举例:批量将id小于3的用户性别改为男,在映射文件中直接写<号,xml约束会报错!
<select id="findUsersLt" resultMap="userMap">select * from user where id < #{id}</select>
第三章 mybatis高级查询【掌握】
3.1 mybatis高级查询环境准备
表与表的关系:
一对一: ab两表的关系,由任意一张表维护(外键) 比如:b表维护ab的管理,那么在b表中创建一个字段aid,但是这个字段不添加外键约束;
一对多:ab两张表 比如:从a看是一个a对应b的多条数据,但是从b看是一个b只能对应一个a的数据;
多对多:ab两张表 比如:从a看是一个a对应b的多条数据,同时从b看是一个b对应a表的多条数据;
说明:通过用户,订单,商品,已经订单商品明细表练习多表关联查询操作;
【1】包结构
创建java项目,导入jar包和log4j日志配置文件以及连接数据库的配置文件;
【2】导入SQL脚本
运行资料中的sql脚本:**mybatis.sql**<br />
【3】创建实体来包,导入资料中的pojo
【5】配置UserMapper.xml映射文件和接口
注:可以根据id查询用户信息为例搭建起工程;<br />1.定义接口
public interface UserMapper {/*** 根据id查询用户信息* @param id* @return*/User findByUserId(@Param("id") Long id);}
2.配置映射文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.heima.mapper.UserMapper"><select id="findByUserId" resultType="user">select * from tb_user where id=#{id}</select></mapper>
3.单元测试
public class TestAll {@Testpublic void test1(){UserMapper mapper = MybatisUtil.getMapper(UserMapper.class);User user = mapper.findByUserId(1l);System.out.println(user);MybatisUtil.close();}}
工程结构:
3.2 一对一查询
一对一映射语法格式:
<resultMap id="映射ID" type="主表实体名称" autoMapping="true" ><!-- 添加主表语主表实体映射 -->......<!--association:配置关联对象(User)的映射关系,一般与resultMap标签联合使用 --><association property="主表实体中对应从表的属性名称" javaType="从表实体类型" autoMapping="true"><!-- 添加从表中字段与实体属性映射关系 --></association></resultMap>
需求:通过订单编号20140921003查询出订单信息,并查询出下单人信息。
说明:一个订单只能对应一个用户信息;
3.1 需求分析
两种实现方式:
-- 方式1:分步查询-- 1.1根据订单编号查询订单信息select * from tb_order where order_number='20140921003';-- user_id:1-- 1.2根据user_id=1查询下单人信息select * from tb_user where id=1;-- 方式2:关联查询select tb_order.id as order_id,tb_order.order_number,tb_user.*from tb_order,tb_userwheretb_user.id=tb_order.user_idand tb_order.order_number='20140921003';
3.2 订单实体添加属性映射
public class Order {private Integer id;private String orderNumber;private User orderUser;//getter setter toString}
3.3 添加order接口及方法
public interface OrderMapper {/*** 根据订单编号查询订单信息,包含下单人信息* @param orderNumber* @return*/Order findOrderByOrderNumber(@Param("orderNumber") String orderNumber);}
3.4 创建order映射文件,编写SQL
说明:配置关联对象一对一映射关系,语法格式:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.heima.mapper.OrderMapper"><!--自定义映射规则--><resultMap id="orderMap" type="Order" autoMapping="true"><id column="order_id" property="id"/><result column="order_number" property="orderNumber"/><!--association:表示一对一映射property="orderUser":表示指定映射的属性名称javaType="User":指定映射属性的类型autoMapping="true":开启自动映射(查询字段名称与pojo类中属性名称一致,可以不写)--><association property="orderUser" javaType="User" autoMapping="true"><id column="id" property="id"/><result column="user_name" property="userName"/></association></resultMap><select id="findOrderByOrderNumber" resultMap="orderMap">selecttb_order.id as order_id,tb_order.order_number,tb_user.*from tb_order,tb_userwhere tb_user.id = tb_order.user_idand tb_order.order_number = #{orderNumber}</select></mapper>
3.5 测试
@Testpublic void test2(){OrderMapper mapper = MybatisUtil.getMapper(OrderMapper.class);Order order = mapper.findOrderByOrderNumber("20140921003");System.out.println(order);MybatisUtil.close();}
3.6 效果
一对一查询总结:
1.映射规则配置?
PPT演示:
2.一对一关联查询实现步骤?
1)维护pojo对象之间一对一的关系:eg:Order 包含属性:User类型的变量2)配置一对一的映射关系<resultMap id="唯一标识" type="映射的类" autoMapping="true"><id column="主键字段" property="映射类中属性名称"/><result column="非主键字段" property="映射类中属性名称"/><!--一对一映射--><association property="映射的类中属性名称" javaType="java类型" autoMapping="true"><id column="主键字段" property="java类型中属性名称"/><result column="非主键字段" property="java类型中属性名称"/></association></resultMap>
3.3.一对多查询TODO
核心映射标签预览:
<!--配置一对多关系映射--><resultMap id="xx" type="xx" autoMapping="true"><!--user表主键映射--><id column="xx" property="xx"/><!--映射实体类中List<Order>集合使用功能Collection标签--><collection property="xxx" javaType="list" ofType="xxx" autoMapping="true"><!--主键映射--><id column="xx" property="xx"/><result column="xx" property="xx"/></collection></resultMap>
需求:查询id为1的用户及其订单信息
【分析】
一个用户可以有多个订单。
一个订单只能属于一个用户。
用户(1)——-订单(n)
-- 方式1:分步查询-- 1.1 根据id查询用户信息select * from tb_user where id=1; -- id=1-- 1.2 根据用户id查询订单集合select * from tb_order where user_id=1;-- 方式1:一步查询selecttb_user.*,tb_order.id as order_id,tb_order.order_numberfrom tb_user,tb_orderwhere tb_user.id = tb_order.user_idand tb_user.id = 1;
【步骤】
第一步:查询SQL分析;第二步:添加关联关系;第三步:编写接口方法;第四步:编写映射文件;第五步:测试
【实现】
1.User实体添加映射关系
public class User implements Serializable{private List<Order> orders;private Long id;// 用户名private String userName;// 密码private String password;// 姓名private String name;// 年龄private Integer age;//0-女 1-男private Integer sex;// getter and setter and toString}
2.编写接口
/*** 根据用户id查询用户信息,包含订单集合信息* @param id* @return*/User findUserAndOrdersByUserId(@Param("id") Long id);
3.编写sql映射文件关联订单集合
<!--定义一对多的映射规则--><resultMap id="userMap" type="user" autoMapping="true"><!--映射主表--><id column="id" property="id"/><result column="user_name" property="userName"/><!--配置一对多映射--><collection property="orders" javaType="list" ofType="order" autoMapping="true"><id column="order_id" property="id"/><result column="order_number" property="orderNumber"/></collection></resultMap><select id="findUserAndOrdersByUserId" resultMap="userMap">selecttb_user.*,tb_order.id as order_id,tb_order.order_numberfrom tb_user,tb_orderwhere tb_user.id = tb_order.user_idand tb_user.id = #{id}</select>
4.测试:
@Testpublic void test3(){UserMapper mapper = MybatisUtil.getMapper(UserMapper.class);User user = mapper.findUserAndOrdersByUserId(1l);System.out.println(user);MybatisUtil.close();}
5.效果
一对多总结:
1.映射规则配置?
PPT演示:
映射示意图:
小结:
1.在一对多的场景中,一般主表中通过创建一个集合属性来包含从表的数据
如:user类包含List\<Order> orders);
2.如何使用collection标签建立对集合的关联映射?
<!--一对多映射--><resultMap id="唯一标识" type="映射的类" autoMapping="true"><id column="主键字段" property="映射类中属性名称"/><result column="非主键字段" property="映射类中属性名称"/><!--一对一映射--><collection property="映射的类中属性名称" javaType="list" ofType="集合泛型" autoMapping="true"><id column="主键字段" property="java类型中属性名称"/><result column="非主键字段" property="java类型中属性名称"/></collection></resultMap>
3.4 多对多查询
多对多查询本质是一对多和一对一查询的组合,核心标签用法如下:
<!--多对多映射--><resultMap id="xx" type="xx" autoMapping="true"><!--主表主键映射--><id column="xx" property="xx"/><collection property="xx" javaType="list" ofType="xx" autoMapping="true" ><!--主表主键映射--><id column="xx" property="xx"/><!-- 一对一映射 --><association property="xx" javaType="xx" autoMapping="true"><!--主表主键映射--><id column="xx" property="xx"/></association></collection></resultMap>
【需求】:查询订单号为20140921001的订单的详情信息即查询订单信息+订单中的商品信息;
【步骤】
第一步:需求分析;第二步:添加关联关系;第三步:编写SQL;第四步:配置关联关系;第五步:运行;
【需求分析】
1、查询订单详情信息即:查询订单信息+订单中的商品信息;2、订单信息在tb_order中,订单中的商品信息在tb_item中,这两个表是通过中间表 tb_orderdetail进行关联的。3、关联查询思路:先查询订单表,通过订单表中的id关联中间表order_id,然后查询中间表,根据中间表的item_id关联商品表的id,最后查询商品表;
第一步:分析sql查询的实现思路
第二步:添加类属性关联关系
1)一个订单表中关联了多个订单详情信息,所以在订单表中添加List<Orderdetail>属性;
2)一条订单详情记录中都包含了一条商品信息,所以需要在Orderdetail中添加一个Item属性;
第三步:编写接口方法
在OrderMapper接口中新增,根据orderNumber查询订单及订单详情的方法;
第四步:编写SQL映射文件
说明:一定要记住这里给order表的id起别名是order_id,订单详情表的id起别名是detail_id,商品表item的id起别名是item_Id。在resultMap标签的id子标签中的column属性值书写对应的order_id、detail_id和item_Id.
第五步:测试
3.5 多表查询扩展
【需求】根据订单号(20140921001)
查询订单信息
查询订单所属用户信息
查询订单中的详细商品信息
1)接口方法
2)映射文件
3)测试
3.6 ResultMap继承extend
如果两个ResultMap结果集有重叠的部分,可以通过extend属性继承简化;<br />继承后简化映射文件配置:
<resultMap id="orderMap4" type="order" extends="orderMap2" autoMapping="true"><association property="user" javaType="user" autoMapping="true"><id column="user_id" property="id"/><result column="user_name" property="userName"/></association></resultMap>
3.7 高级查询小结
前提:查询的字段必须唯一!
一对一:一对多:多对多:
重点:
1)一对一映射配置
2)一对多映射配置
3)动态sql标签
4)#{}和${}区别(面试)
第四章 mybatis延迟加载【了解】
1、延迟加载概述
- 应用场景
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。 - 延迟加载的好处
先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。 - 延迟加载的条件:
1)resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
2)延迟加载是针对分步查询而言的
2、开启延迟加载
Mybatis的延迟加载功能默认是关闭的
需要在mybatis-config.xml全局配置文件中通过setting标签配置来开启延迟加载功能开启延迟加载的属性:需要在mybatis-config.xml全局配置文件中通过setting标签配置来开启延迟加载功能
【示例】lazyLoadingEnabled:全局性设置懒加载。默认为false,true表示开启延迟加载aggressiveLazyLoading:false表示关闭积极加载说明:这两个属性必须一起设置
<settings><!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/><!--关闭积极加载--><setting name="aggressiveLazyLoading" value="false"/></settings>
3、延迟加载测试
延迟加载需求:通过订单编号20140921003查询order并延迟加载user。就是演示上述演示过的一对一的表关系案例。分析:
如果改成延迟加载,也就意味着,先查询order,等需要的时候再去查询user,那就相当于将上面的一条语句变成了两条语句:
1、通过订单编号查询order
2、通过查询出来的order中的user_id查询user
SQL语句:分步查询:#第一步:根据order_number查询订单信息;SELECT * FROM tb_order WHERE order_number = '20140921003';#第二步:根据订单信息中的user_id查询出下单人的信息;SELECT * FROM tb_user WHERE id = 1;
第一步:编写接口方法及映射文件
1.在OrderMapper接口中新建:queryOrderUserLazy方法;
2.编写映射文件,分部查询,通过association标签下的column和select属性获取参数并传递到子查询中;Order queryOrderUserLazy(String orderNumber);
<!--引入在查询order信息的同事需要将用户的信息一并封装到order实体下,需要进行高级映射--><resultMap id="orderUserLazyMap" type="order" autoMapping="true"><!--主键映射--><id column="order_id" property="id"/><!--普通字段映射 order_number:orderNumber, 因为settting中设置了驼峰规则,所以可省略--><result column="order_number" property="orderNumber"/><!--用于映射user对象,关系:一对一,可使用association实现映射--><association property="user" javaType="user" column="user_id" select="com.heima.dao.UserMapper.queryById"></association></resultMap><select id="queryOrderUserLazy" resultMap="orderUserLazyMap">select * from tb_order where order_number=#{orderNumber}</select>
第二步:开启懒加载
在mybatis-config.xml全局配置文件中,开启懒加载;<settings><!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/><!--关闭积极加载--><setting name="aggressiveLazyLoading" value="false"/></settings>
第三步:测试
小结:@Testpublic void queryOrderUserLazy(){Order order = orderMapper.queryOrderUserLazy("20140921001");System.out.println("此时没有进行用户信息查询");System.out.println(order.getOrderNumber());//当我们使用user对象时,才从数据库中加载User user = order.getUser();System.out.println(user.toString());}
延迟加载的利与弊
好处:先从单表进行查询数据,需要时再从关联表去关联查询,将会提高数据库性能,因为查询单表要比关联查询多张表速度快。
坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
