mybatis 懒加载

懒加载原理

懒加载是为改善,解析对象属性时大量的嵌套子查询的并发问题。设置懒加载后,只有在使用指定属性时才会加载,从而分散SQL请求。
通过对Bean的动态代理,重写所有属性的getXxx方法。在获取属性前先判断属性是否被加载,如果否则加载。
调用流程图如下:
在这里插入图片描述

其中第一步的Bean代理过程发生在结果集解析 交创建对象之后(DefaultResultSetHandler.createResultObject),如果对应的属性设置了懒加载,则会通过ProxyFactory 创建代理对象,该对象继承自原对象,然后将对象的值全部拷贝到代理对像。并设置相应MethodHandler(原对象直接抛弃)

在这里插入图片描述

下面我们来看看代理后的结构在这里插入图片描述

调试时的属性值如下:
在这里插入图片描述

需要注意的是懒加载只会触发一次,因为执行懒加载的时候在map中移除了:
在这里插入图片描述

开启方法

懒加载的开启方式有以下几种:
lazyLoadingEnabled 全局懒加载开关 默认false
aggressiveLazyLoading 任意方法触发加载 默认false。
fetchType 加载方式 eager实时 lazy懒加载。默认eager

在调用对象配置了懒加载属性的的get方法,如:

    <resultMap id="blogMap" type="com.entity.Blog" autoMapping="true">
        <result column="title" property="title"></result>
        <collection property="comments" column="id" select="selectCommentsByBlogId" fetchType="lazy">
        </collection>
    </resultMap>

调用了getComments会触发懒加载,
或者调用对象的"equals", “clone”, “hashCode”, “toString” 均会触发当前对象所有未执行的懒加载,源码位置:
在这里插入图片描述

验证几种操作还会不会触发懒加载

  1. 先调用配置了懒加载的set方法,再调用get方法的情况
@Test
    public void lazySetTest(){
        Blog blog=blogMapper.selectBlogById(1);
        blog.setComments(new ArrayList<>());
        for(Comment comment:blog.getComments()){
            System.out.println(DateUtil.formatDate(comment.getDate())+"评论了本博客:"+comment.getContent());
        }
        System.out.println(blog.getComments());
    }

在这里插入图片描述
我们可以看到不能获取到comments的记录,而正常情况下是可以的,说明被我们设置后的属性会使得懒加载失效

2、 序列化与反序列化的情况

   <!--懒加载-->
    <resultMap id="blogMap" type="com.entity.Blog" autoMapping="true">
        <result column="title" property="title"></result>
        <collection property="comments" column="id" select="selectCommentsByBlogId" fetchType="lazy">
        </collection>
    </resultMap>
@Before
    public void init(){
        DruidDataSource druidDataSource=new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/test");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        druidDataSource.setValidationQuery("select 1");
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("development", transactionFactory, druidDataSource);
        configuration = new Configuration(environment);

        
//测试懒加载序列化时需要自行设定一个configurationFactory的类。
        configuration.setConfigurationFactory(LazyTest.ConfigurationFactory.class);
        configuration.addMapper(BlogMapper.class);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        this.session=sqlSessionFactory.openSession();
        blogMapper=session.getMapper(BlogMapper.class);
    }
/**
     * 测试序列化和反序列化
     */
    @Test
    public void lasySerializableTest() throws IOException, ClassNotFoundException {
        Blog blog=blogMapper.selectBlogById(1);
        byte[] bytes=writeObject(blog);
        Blog newBlog= (Blog) readObject(bytes);
        System.out.println("反序列化完成");
        newBlog.getComments();
    }

    private static byte[] writeObject(Object object) throws IOException {
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
        objectOutputStream.writeObject(object);
        return out.toByteArray();
    }

    private static Object readObject(byte[] bytes) throws IOException, ClassNotFoundException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        return objectInputStream.readObject();
    }

在这里插入图片描述
我们可以看到,在反序列化后,还是能调用成功,是因为在序列化过程中时,会通过实现Externalizable接口的writeExternal()和readExternal() 两个方法将相关的环境变量设置和还原,使得懒加载能正常生效,相关源码如下:
在这里插入图片描述

本文章的参考资料为:
https://www.coderead.cn/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值