likes
comments
collection
share

水煮MyBatis(十六)- 延迟加载(上)

作者站长头像
站长
· 阅读数 50

前言

延迟加载,也叫懒加载,是一种对象关联关系的加载方式,被设计用来避免一些无谓的系统性能损耗。毕竟在正常情况下,一个关联对象只有被访问的时候,才有必要去显示;而若所有的访问都返回全部数据,不仅浪费网络带宽,对数据库也是一种消耗。

配置

主要有三个配置

  • lazy-loading-enabled: 全局懒加载配置,如果设置为false,则所有的关联数据都立即返回,默认为false;
  • aggressive-lazy-loading: 是否进行激进的懒加载策略,是一种折中方案,默认为false;如果一个表有多个关联对象,则某个被标注为懒加载的对象被加载以后,其他所有的关联对象,无论是否标注为懒加载,都全部加载;
  • lazy-load-trigger-methods: 这个属性就是字面意思,触发懒加载的方法;默认只有四个:equals,clone,hashcode,tostring,毕竟这四个方法基本上都需要对象的全部属性数据,作为一个整体来处理。如果在代码中调用了这四个方法,则对象所有的属性,无论是否标注为懒加载,都全部加载;

默认配置在Configuration类中有体现:

  protected boolean lazyLoadingEnabled = false;
  protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
  protected boolean aggressiveLazyLoading;

注解

网上的懒加载例子,基本都是基于xml文件的,而我从这个系列一开始,就是从注解入手的,所以这里还是考虑使用注解的方式来进行说明。

@Results

例子中没有用到这个注解,之所以提及,是因为在xml文件中,它是结果映射的集合,里面包含了一系列的映射描述,替代了对应的<resultMap/>标签。当然,也有@ResultMap注解,不过这里没有涉及到,就不展开说明了。 在注解的使用方式中,也可以包含一个@Result注解集合,或者单个@Result

    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "name", column = "name")
    })

@Result

这个注解可以单独使用,不依赖@Results,前提是只有一个关联对象的情况下。

  • property:对象里的属性名称;
  • column:数据库表里的字段名称;
  • one:一对一关联关系的设定,需要使用@One注解;
  • many:一对多关联关系的设定,需要使用@Many注解;
    @Result(property = "imageInfo", column = "image_id",
            one = @One(select = "com.essay.mybatis.mapper.ImageInfoMapper.selectByPrimaryKey",
                    fetchType = FetchType.LAZY))

@One

一对一关联关系的设定

  • select:查询数据的MapedStatement,具体指向的是一个查询方法;
  • fetchType:有三种类型可供选择,默认是的DEFAULT,可选的是:LAZY,EAGER,懒加载或者立即加载;

@Many

一对多关联关系的设定,使用方式与@One类似,就不重复描述了。

例子

配置

mybatis:
  configuration:
    lazy-loading-enabled: true
    aggressive-lazy-loading: false
    lazy-load-trigger-methods: " "

表对象

@Table(name = "tb_item")
@Data
public class Item implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    /**
     * 名称
     */
    private String name;
    /**
     * 编码
     */
    private String code;
    /**
     * 状态,0 初始化;1:上架,2:下架
     */
    private Integer status;
    /**
     * 图片id
     */
    private ImageInfo imageInfo;

}

查询方法

    @Select("select * from tb_item where id = #{id}")
    @Result(property = "imageInfo", column = "image_id",
            one = @One(select = "com.essay.mybatis.mapper.ImageInfoMapper.selectByPrimaryKey",
                    fetchType = FetchType.LAZY))
    Item byId(@Param(value = "id") int id);

测试方法

    public void select(int id) {
        Item item = itemMapper.byId(id);
        log.info("=>,{}", item.getName());
        log.info("=>,111");
        log.info("=>,222");
        log.info("=>,333");
        log.info("=>,444");
        log.info("=>,555");
        log.info("=>,{}", item.getImageInfo());
    }

输出结果

JDBC Connection [HikariProxyConnection@1272257854 wrapping com.mysql.cj.jdbc.ConnectionImpl@33425811] will be managed by Spring
==>  Preparing: select * from tb_item where id = ?
==> Parameters: 1(Integer)
<==    Columns: id, name, code, status, image_id, create_time, update_time
<==        Row: 1, 测试物品, P121212SDFA, 1, 1, 2022-05-20 11:08:48, 2022-05-20 11:08:48
<==      Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@aaa0f76]
18:08:59.797 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,测试物品
18:08:59.798 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,111
18:08:59.798 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,222
18:08:59.798 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,333
18:08:59.798 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,444
18:08:59.798 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,555
Cache Hit Ratio [com.essay.mybatis.mapper.ImageInfoMapper]: 0.0
==>  Preparing: SELECT id,md5,img_url,status,first_job_id,create_time,update_time FROM tb_image WHERE id = ?
==> Parameters: 1(Integer)
<==    Columns: id, md5, img_url, status, first_job_id, create_time, update_time
<==        Row: 1, 6e705a7733ac5gbwopmp02, https://fp-dev.webapp.163.com/editor/file/6180a730173f910ee764dbe1XL8iO2No02, 50, 12, 2022-04-14 16:37:31, 2022-05-13 16:15:00
<==      Total: 1
18:08:59.801 logback [main] INFO  c.essay.mybatis.service.ItemService - =>,ImageInfo(id=1, md5=6e705a7733ac5gbwopmp02, imgUrl=https://fp-dev.webapp.163.com/editor/file/6180a730173f910ee764dbe1XL8iO2No02, status=50, firstJobId=12, createTime=Thu Apr 14 16:37:31 CST 2022, updateTime=Fri May 13 16:15:00 CST 2022)

结果说明

从输出结果中可以看到,一开始的查询itemMapper.byId(id),并没有触发imageInfo的加载,直到日志输出语句中,调用item.getImageInfo()时,才执行了子查询SELECT id,md5,img_url,status,first_job_id,create_time,update_time FROM tb_image WHERE id = ?,说明例子中的懒加载配置产生了我们预期的效果。

转载自:https://juejin.cn/post/7246206157898399802
评论
请登录