zoukankan      html  css  js  c++  java
  • MyBatis Lazy Loading

    MyBatis的Lazy Loading可以实现延迟查询Bean里的嵌套成员类,控制lazy loading的<settings>属性有

    lazyLoadingEnabled: lazy loading开关,默认为true

    aggressiveLazyLoading: 侵略性 lazy loading 开关, 默认为true, 这个属性比较搞笑,如果为true则当你访问任何一个属性都会加载所有的其他lazy load属性,即使你根本没有调用哪个lazy load属性,说白了就是aggressiveLazyLoading=true,则lazy load等于没用,所以要使用lazy load还是将其设为false

    一个使用lazyload的例子

    ResultMap

        <!-- 使用子查询的方式查询成员变量 -->
        <resultMap id="articleResultMap2" type="Article">
            <id property="id" column="article_id" />
            <result property="title" column="article_title" />
            <result property="content" column="article_content" />
            <association property="user" column="user_id" select="dao.userdao.selectUserByID"/>
        </resultMap>

    查询Mapper

        <!-- 测试lazy load user -->
        <select id="selectArticleById2" parameterType="int" resultMap="dao.base.articleResultMap2">
            SELECT * FROM article WHERE id = #{id}
        </select>
    
        <select id="selectUserByID" parameterType="int" resultType="User"
                flushCache="false" useCache="true" timeout="10000" statementType="PREPARED">
            SELECT
                *
            FROM user
            WHERE id = #{id}
        </select>

    测试代码

        public String getArticle2(Model model) {
            Article article = articleDao.selectArticleById2(1);
            // 如果你在这里打一个断点,你会发现还没有执行到getUser()这一句article.user已经被查询加载
            // 而如果你将 getUser() 那行注释,则article.user在执行到这里也不会被加载
            // 我的理解是java是编译型语言,mybatis可以根据编译好的中间码查看哪些属性被调用
            // 然后在第一次执行sql的时候把后面将会调用到的延迟加载属性都提前加载了
            // 另外,MyBatis有个更搞笑和骗人的地方是,如果你不在这里打断点,它lazy load的子查询就一定会出现在getUser()之后
            // 而如果这里打了断点,则lazy load的子查询语句会在selectArticleById2()这个方法就出现了
            System.out.println();
            // 如果aggressiveLazyLoading为true,则getContent()的时候就会执行查询user的sql
            // 即使你根本没有调用getUser(),也会将user属性查询出来,例如将getUser()那行注释了
            System.out.println(article.getContent());
            System.out.println("Lazy loading ......");
            System.out.println(article.getUser());
            return "index";
        }

    输出

    DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
    DEBUG - ==> Preparing: SELECT * FROM article WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - Cache Hit Ratio [dao.userdao]: 0.0
    DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6bbe7]
    DEBUG - Returning JDBC Connection to DataSource

    test_content
    Lazy loading ......
    DEBUG - Fetching JDBC Connection from DataSource
    DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
    DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
    DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - Returning JDBC Connection to DataSource
    1|test1|19|beijing

    抛开上面注释中MyBatis各种奇怪的表现不说,MyBatis的Lazy Loading是基于子查询select的,也是这段

    <association property="user" column="user_id" select="dao.userdao.selectUserByID"/>

    这个方式最大的问题是会产生N+1问题,假设article里的user是一个List<User>:

    1. 使用一条SQL语句查询Article类(the 1)

    2. 使用N条SQL查询Article里的List<User>

    如果我们在查询Article以后需要遍历Article的List<User>,则会触发所有user的Lazy Loading

    也就是说我们也无法使用JOIN去使用Lazy Loading,从而避免n+1的问题

  • 相关阅读:
    shell Builtin variables(shell内建变量)
    [置顶] 九度笔记之 1434:今年暑假不AC
    OpenRisc-45-or1200的ID模块分析
    hdu1556 Color the ball
    PB C/S轉B/S ODBC方式連接數據庫
    Django的安装配置和开发
    通过一个月时间字段分组
    如何加入该网站for Linux(绑定域名)
    LeetCode 36 Sudoku Solver
    POJ 1986 Distance Queries LCA两点距离树
  • 原文地址:https://www.cnblogs.com/zemliu/p/3241025.html
Copyright © 2011-2022 走看看