Mybatis(二)加载策略及注解开发

本文详细介绍了MyBatis的加载策略,包括延迟加载和立即加载的优缺点及其应用场景。在多对一和一对多的关系中,通常采用延迟加载以提高数据库性能。同时,文章讨论了一级缓存和二级缓存的工作原理,一级缓存是SqlSession级别的,而二级缓存是namespace级别的,两者都可提高查询效率,但二级缓存可能导致脏读问题。MyBatis的注解开发简化了Mapper配置,同时也支持注解形式的延迟加载。文章最后对比了注解开发和XML配置的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MyBatis加载策略

什么是延迟加载?

  • 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
    • 优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 速度要快。 *
    • 缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时 间,所以可能造成用户等待时间变长,造成用户体验下降。
      • 在多表中: 一对多,多对多:通常情况下采用延迟加载
    • 一对一(多对一):通常情况下采用立即加载 *
    • 注意:延迟加载是基于嵌套查询来实现的
  •    <!--fetchType="lazy" : 延迟加载策略
          fetchType="eager": 立即加载策略
      -->
      <collection property="ordersList" ofType="com.lagou.domain.Orders" column="id"
                  select="com.lagou.mapper.OrderMapper.findByUid" ></collection>
    

设置触发延迟加载的方法

大家在配置了延迟加载策略后,发现即使没有调用关联对象的任何方法,但是在你调用当前对象的
equals、clone、hashCode、toString方法时也会触发关联对象的查询。
我们可以在配置文件中使用lazyLoadTriggerMethods配置项覆盖掉上面四个方法。

        <settings>
       
        <setting name="lazyLoadTriggerMethods" value="toString()"/>
        
      
         </settings>

全局延迟加载

<settings>
        <!--开启全局延迟加载功能-->
        <setting name="lazyLoadingEnabled" value="true"/>
          </settings>
  • 局部的加载策略优先级高于全局的加载策略。

MyBatis缓存

为什么使用缓存?

  • 当用户频繁查询某些固定的数据时,第一次将这些数据从数据库中查询出来,保存在缓存中。当用户再次查询这些数据时,不用再通过数据库查询,而是去缓存里面查询。减少网络连接和数据库查询带来的损耗,从而提高我们的查询效率,减少高并发访问带来的系统性能问题。
  • 一句话概括:经常查询一些不经常发生变化的数据,使用缓存来提高查询效率。
  • 像大多数的持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。 Mybatis中缓存分为一级缓存,二级缓存。

一级缓存

  • 介绍

    • 一级缓存是SqlSession级别的缓存,是默认开启的
    • 所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
  • 一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用clearCache()、commit()、close()方法,都会清空缓存。

  •    第一次发起查询用户id为41的用户信息,先去找缓存中是否有id为41的用户信息,如果没有,从数据库 查询用户信息。 
    
       得到用户信息,将用户信息存储到一级缓存中。
       
       如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一
       级缓存,这 样做的目的为了让缓存中存储的是最新的信息,避免脏读。
       
       第二次发起查询用户id为41的用户信息,先去找缓存中是否有id为41的用户信息,缓存中
       有,直接从缓 存中获取用户信息。
    

二级缓存

  • 二级缓存是namspace级别(跨sqlSession)的缓存,是默认不开启的
  • 二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置 就可以开启二级缓存了。
  • 配置核心配置文件
  •   <settings>
      <setting name="cacheEnabled" value="true"/>
       </settings>
     映射里面
      <!--当前映射文件开启二级缓存--> 
      <cache></cache>
    
  • 二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个
    SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
  • 映射语句文件中的所有select语句将会被缓存。
  • 映射语句文件中的所有insert、update和delete语句会刷新缓存。
  • 注意问题(脏读)
  • mybatis的二级缓存因为是namespace级别,所以在进行多表查询时会产生脏读问题

小结

  • mybatis的缓存,都不需要我们手动存储和获取数据。mybatis自动维护的。
  • mybatis开启了二级缓存后,那么查询顺序:二级缓存–》一级缓存–》数据库
  • mybatis的二级缓存会存在脏读问题,需要使用第三方的缓存技术解决问题。

MyBatis注解

MyBatis常用注解

这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写
Mapper映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

    @CacheNamespace // 配置了二级缓存
    public interface UserMapper {
  • @Select:实现查询,代替了
  •       /*
              查询用户
           */
          @Select("select * from user")
          public List<User> findAll();
    
    • @Insert:实现新增,代替了
  •       /*
              添加用户
           */
          @Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
          public void save(User user);
    
  • @Update:实现更新,代替了
  •       /*
              更新用户
           */
          @Update("update user set username = #{username},birthday=#{birthday} where id = #{id}")
          public void update(User user);
    
  • @Delete:实现删除,代替了
  •       /*
              删除用户
           */
          @Delete("delete from user where id = #{id}")
          public void delete(Integer id);
      
      
      
          /*
              根据id查询用户
           */
          @Select("select * from user where id = #{uid}")
          public User findById(Integer uid);
    
  • @Result:实现结果集封装,代替了
  • @Results:可以与@Result 一起使用,封装多个结果集,代替了
  • @One:实现一对一结果集封装,代替了
  • @Many:实现一对多结果集封装,代替了
        /*
            查询所有用户,及关联的订单信息
         */
    
        @Select("select * from user")
        @Results({
                @Result(property = "id",column = "id",id = true),
                @Result(property = "username",column = "username"),
                @Result(property = "birthday",column = "birthday"),
                @Result(property = "sex",column = "sex"),
                @Result(property = "address",column = "address"),
                @Result(property = "ordersList",javaType = List.class,column = "id",many = @Many(select = "com.lagou.mapper.OrderMapper.findOrderByUid",fetchType = FetchType.LAZY))
        })
        public List<User> findAllWithOrder();
    
    
    
    
        /*
            查询所有用户及关联的角色信息
         */
    
        @Select("select * from user")
        @Results({
                @Result(property = "id",column = "id",id = true),
                @Result(property = "username",column = "username"),
                @Result(property = "birthday",column = "birthday"),
                @Result(property = "sex",column = "sex"),
                @Result(property = "address",column = "address"),
                @Result(property = "roleList",javaType = List.class,column = "id",many = @Many(select = "com.lagou.mapper.RoleMapper.findAllByUid")),
        })
        public List<User> findAllWithRole();
    
    
    }

    /*
    查询所有订单,同时查询订单所属的用户信息
 */


    @Select("select * from orders")
    @Results({  // 代替的就是resultMap标签 id标签  result标签
          @Result(property = "id",column = "id",id = true),
          @Result(property = "ordertime",column = "ordertime"),
          @Result(property = "total",column = "total"),
          @Result(property = "uid",column = "uid"),
            @Result(property = "user",javaType = User.class,column = "uid",one = @One(select = "com.lagou.mapper.UserMapper.findById",fetchType = FetchType.EAGER))
    })
    public List<Orders> findAllWithUser();

基于注解的二级缓存

  • 配置SqlMapConfig.xml文件开启二级缓存的支持
  • 在Mapper接口中使用注解配置二级缓存
  • @CacheNamespace
  •    @CacheNamespace //开启注解
       public interface UserMapper {
          ...
           
       }
    

注解延迟加载

  • 不管是一对一还是一对多 ,在注解配置中都有fetchType的属性
    • fetchType = FetchType.LAZY 表示懒加载
    • fetchType = FetchType.EAGER 表示立即加载
    • fetchType = FetchType.DEFAULT 表示使用全局配置

小结

  • 注解开发和xml配置优劣分析
    • 注解开发和xml配置相比,从开发效率来说,注解编写更简单,效率更高。
    • 从可维护性来说,注解如果要修改,必须修改源码,会导致维护成本增加。xml维护性更强

本篇应该算基础应用里面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值