mybaties之关联查询与延迟加载

mybatis专栏 https://blog.csdn.net/worn_xiao/category_6530299.html?spm=1001.2014.3001.5482

一Mybaties关联查询与缓存

基本数据模型:

如上所示是我们电商系统的基本数据模型

1.1 一对一映射

模拟一个订单只能属于一个用户的,一对一映射。

SELECT
 orders.`id`,
 orders.`user_id`,
 orders.`number`,
 user.`username`,
 user.`sex`
FROM
 orders,
 USER
WHERE orders.`user_id` = user.`id`

1.1.1 以resultType作为扩展类

创建可扩展的PO类,扩展订单实体:

publicclass OrdersExt extends Orders{

   

    //添加用户属性

    /*USER.username,

      USER.address */

   

    private String username;

    private String address;

    public String getUsername() {

       returnusername;

    }

    publicvoid setUsername(String username) {

       this.username = username;

    }

    public String getAddress() {

       returnaddress;

    }

    publicvoid setAddress(String address) {

       this.address = address;

    }

   

}

创建mapper映射接口:

public List<OrdersExt> findOrdersUser();

创建映射文件:

<mapper namespace="cn.itcast.mybatis.mapper.OrdersMapper">

 

    <!-- 定义查询订单表列名的SQL片段 -->

    <sql id="select_orders">

       Orders.id,

       Orders.user_id,

       orders.number,

       orders.createtime,

       orders.note

    </sql>

    <!-- 定义查询用户表列名的SQL片段 -->

    <sql id="select_user">

       user.username,

       user.address

    </sql>

    <!-- 进行订单信息查询,包括用户的名称和地址信息 -->

    <select id="findOrdersUser" resultType="OrdersExt">

       Select

       <include refid="select_orders"/>

       <include refid="select_user"></include>

       from orders,user

       where orders.user_id = user.id

    </select>

</mapper>

加载映射文件

<!-- 批量加载mapper文件,需要mapper接口文件和mapper映射文件名称相同且在同一个包下 -->
<package name="cn.itcast.mybatis.mapper"/>

测试代码

@Test

publicvoid testFindOrdersUser(){

    // 创建sqlSession

    SqlSession sqlSession = sqlSessionFactory.openSession();

 

    // 通过SqlSession构造usermapper的代理对象

    OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);

    // 调用usermapper的方法

    List<OrdersExt> list = ordersMapper.findOrdersUser();

 

    System.out.println(list);

 

    // 释放SqlSession

    sqlSession.close();

}

1.1.2 以resultMap作为扩展

 vo实体类

publicclass Orders {

    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

private String note;

private User user;

mapper接口:

public List<OrdersExt> findOrdersUserRstMap();

<!-- 进行订单信息查询,包括用户的名称和地址信息 (ResultMap)-->

    <select id="findOrdersUserRstMap" resultMap="OrdersUserRstMap">

       Select

       <include refid="select_orders"/>

       ,

        <include refid="select_user"></include>

       from orders,user

       where orders.user_id = user.id

xml映射文件

</select>

 

    <!-- 定义orderUserResultMap -->

    <resultMap type=" cn.itcast.mybatis.po.Orders" id="OrdersUserRstMap">

       <id column="id"property="id" />

       <result column="user_id"property="userId" />

       <result column="number"property="number" />

       <result column="createtime"property="createtime" />

       <result column="note"property="note" />

       <!-- 映射一对一关联关系的用户对象-->

       <!--

           property:指定关联对象要映射到Orders的哪个属性上

           javaType:指定关联对象所要映射的java类型

         -->

       <!-- id标签:指定关联对象结果集的唯一标识,很重要,不写不会报错,但是会影响性能 -->

       <association property="user"javaType="cn.itcast.mybatis.po.User">

           <id column="user_id"property="id" />

           <result column="username"property="username" />

           <result column="address"property="address" />

       </association>

    </resultMap>

测试代码

@Test

publicvoid testFindOrdersUserRstMap() {

    // 创建sqlSession

    SqlSession sqlSession = sqlSessionFactory.openSession();

 

    // 通过SqlSession构造usermapper的代理对象

    OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);

    // 调用usermapper的方法

    List<Orders> list = ordersMapper.findOrdersUserRstMap();

      

    //此处我们采用debug模式来跟踪代码,然后验证结果集是否正确

    System.out.println(list);

    // 释放SqlSession

    sqlSession.close

 

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

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

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

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

1.2 一对多映射

业务场景描述:一个订单有多个订单明细。

Select

         Orders.id,

         Orders.user_id,

         orders.number,

orders.createtime,

orders.note,

user.username,

user.address,

orderdetail.iddetail_id,

orderdetail.items_id,

orderdetail.items_num

from orders,user,orderdetail

where orders.user_id = user.id

         andorders.id = orderdetail.orders_id

 

修改订单实体

在Orders类中添加以下属性,并提供get/set方法:

//订单明细

private List<Orderdetail> detailList;

mapper接口

// 查询订单信息及订单明细信息(一对多映射之使用resultMap)

public List<Orders> findOrdersAndOrderdetailRstMap();

编写映射文件Mapper.xml

<!-- 定义OrdersAndOrderdetailRstMap -->

<!-- extends:继承已有的ResultMap,值为继承的ResultMap的唯一标示 -->

<resultMap type="Orders"id="OrdersAndOrderdetailRstMap"

    extends="OrdersUserRstMap">

       <!-- 映射关联关系(一对多) -->

       <!-- collection标签:定义一个一对多关系

           ofType:指定该集合参数所映射的类型

        -->

       <collection property="detailList"ofType="Orderdetail">

           <id column="detail_id"property="id" />

           <result column="items_id"property="itemsId" />

           <result column="items_num"property="itemsNum" />

       </collection>

    </resultMap>

 

<!-- 查询订单信息,包括用户名称、用户地址,订单商品信息(嵌套结果) -->

<select id="findOrdersAndOrderdetailRstMap"resultMap="OrdersAndOrderdetailRstMap">

 

       Select

       <include refid="select_orders"/>,

       <include refid="select_user"/>,

       orderdetail.id detail_id,

       orderdetail.items_id,

       orderdetail.items_num

       from orders,user,orderdetail

       where orders.user_id = user.id

       and

       orders.id = orderdetail.orders_id

 

    </select>

resultMap的extends属性:可以用此属性来继承一个已有的resultmap。但是它继承的resultMap的type和它本身的type要保持一致。通过resultmap的继承,可以减少mapper的冗余映射。

测试代码

@Test

publicvoid testFindOrdersAndOrderdetailRstMap() {

    // 创建sqlSession

    SqlSession sqlSession = sqlSessionFactory.openSession();

 

    // 通过SqlSession构造usermapper的代理对象

    OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);

    // 调用usermapper的方法

    List<Orders> list = ordersMapper.findOrdersAndOrderdetailRstMap();

      

    //此处我们采用debug模式来跟踪代码,然后验证结果集是否正确

    System.out.println(list);

    // 释放SqlSession

    sqlSession.close();

mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。

1.3 多对多映射

用户信息与商品信息的多对多关系

select

         Orders.id,

         Orders.user_id,

         orders.number,

orders.createtime,

orders.note,

user.username,

user.address,

orderdetail.iddetail_id,

orderdetail.items_id,

orderdetail.items_num

 items.name items_name,

 items.detail items_detail 

FROM

 orders,

USER,

 orderdetail,

 items

WHERE user.`id` = orders.`user_id`

  ANDorders.`id` = orderdetail.`orders_id`

  ANDorderdetail.`items_id` = items.`id`

修改实体信息,分别在用户中添加订单信息,订单中添加订单明细,订单明细中添加订单项

在user类中添加List<Orders> ordersList 属性

// 订单信息

private List<Orders> ordersList;

在Orders类中添加List<Orderdetail>属性

//订单明细

private List<Orderdetail> detailList;

在Orderdetail类中添加Items属性

//商品信息

private Items items;

接口定义

//查询用户及用户购买商品信息(多对多映射之使用resultMap)

public List<User> findUserAndItemsRstMap();

编写映射文件

<!-- 定义UserAndItemsRstMap -->

    <resultMap type="User" id="UserAndItemsRstMap">

       <!-- 用户信息 -->

       <!-- id:关联查询用户的唯一标示 -->

       <id column="user_id"property="id" />

       <result column="username"property="username" />

       <result column="address"property="address" />

       <!-- 订单信息(一个用户有多个订单) -->

       <collection property="ordersList"ofType="orders">

           <id column="id"property="id" />

           <result column="user_id"property="userId" />

           <result column="number"property="number" />

           <result column="createtime"property="createtime" />

           <result column="note"property="note" />

           <!-- 订单明细信息(一个订单有多个订单明细) -->

           <collection property="detailList"ofType="orderdetail">

              <id column="detail_id"property="id" />

              <result column="items_id"property="itemsId" />

              <result column="items_num"property="itemsNum" />

              <!-- 商品信息(一个订单明细对应一个商品) -->

              <association property="items"javaType="cn.itcast.mybatis.po.Items">

                  <id column="items_id"property="id" />

                  <result column="items_name"property="name" />

                  <result column="items_detail"property="detail" />

              </association>

           </collection>

       </collection>

    </resultMap>

 

    <!-- 查询用户及用户购买商品信息(多对多映射之使用resultMap) -->

    <select id="findUserAndItemsRstMap" resultMap="UserAndItemsRstMap">

       Select

       <include refid="select_orders"/>

       ,

       <include refid="select_user"/>

       ,

       <include refid="select_orderdetail"></include>

       ,

       items.name items_name,

       items.detail items_detail

       from

       orders,user,orderdetail,items

       where orders.user_id = user.id

       and

       orders.id = orderdetail.orders_id

       and orderdetail.items_id = items.id

    </select>

编写测试代码:

@Test

    publicvoid testFindUserAndItemsRstMap() {

       // 创建sqlSession

       SqlSession sqlSession = sqlSessionFactory.openSession();

       // 通过SqlSession构造usermapper的代理对象

       OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);

       // 调用usermapper的方法

       List<User> list = ordersMapper.findUserAndItemsRstMap();

       // 此处我们采用debug模式来跟踪代码,然后验证结果集是否正确

        System.out.println(list);

       // 释放SqlSession

       sqlSession.close();

    }

1.3.1 关联映射总结

resultType:

作用:将查询结果按照sql列名pojo属性名一致性映射到pojo中。

场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。

resultMap:使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。

association:

作用:将关联查询信息映射到一个pojo对象中。

场合:为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。

使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。

        

collection:

作用:将关联查询信息映射到一个list集合中。

场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。

         如果使用resultType无法将查询结果映射到list集合中。

1.4 延迟加载

resultMap中的association和collection标签具有延迟加载的功能。

延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

Mybatis默认是不开启延迟加载功能的,我们需要手动开启。

需要在SqlMapConfig.xml文件中,在<settings>标签中开启延迟加载功能。

lazyLoadingEnabled、aggressiveLazyLoading

<settings>

         <!-- 开启延迟加载,默认是false -->

                   <setting name="lazyLoadingEnabled"value="true"/>

                   <!--积极的懒加载模式,默认是false-->

                   <setting name="aggressiveLazyLoading"value="false"/>

</settings>

<!-- 定义OrdersUserLazyLoadingRstMap -->

<resultMap type="cn.itcast.mybatis.po.Orders"id="OrdersUserLazyLoadingRstMap">

    <id column="id" property="id"/>

    <result column="user_id" property="userId"/>

    <result column="number" property="number"/>

    <result column="createtime" property="createtime" />

    <result column="note" property="note"/>

      

    <!-- 延迟加载用户信息 -->

    <!-- select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)

       我们使用UserMapper.xml中的findUserById完成根据用户ID(user_id)查询用户信息

       如果findUserById不在本mapper中,前边需要加namespace

    -->

    <!-- column:主信息表中需要关联查询的列,此处是user_id -->

    <association property="user" select="cn.itcast.mybatis.mapper.UserMapper.findUserById"column="user_id"></association>

</resultMap>

 

<!-- 查询订单信息,延迟加载关联查询的用户信息 -->

<select id="findUserById" parameterType="int"

       resultType="cn.itcast.mybatis.po.User">

    SELECT * FROM user WHERE id = #{id}

</select>

如上图所示通过懒加载关联查询用户信息。

映射文件

<package name="cn.itcast.mybatis.mapper"/>

查询订单信息

// 查询订单信息,延迟加载关联查询的用户信息

public List<Orders> findOrdersUserLazyLoading();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值