zoukankan      html  css  js  c++  java
  • Mybatis一级缓存的锅

    问题背景

    项目开发中有一个树形数据结构,不像经典组织结构树、菜单级别树,我们这个树形结构是用户后期手动建立起来的关系。因此数据库表结构为两张表:数据记录表、记录关系表,通过业务规则限制,形成的树形结构像下面这样:

    特殊之处就是树结构节点是有重复的

    • 不复制重复节点
      5NVrIU.png

    • 复制重复节点

    5NVDaT.png

    项目要求前端展示、导出时使用复制重复节点的方式。开搞吧

    Mybatis树结构查询

    树结构查询,在mysql下当然是使用Mybatis框架提供的递归查询了。

    1. xml配置文件
    <resultMap type="(...).OKRAlignTreeNode" id="TreeNodeResult">
        <result property="id"    column="objective_id"    />
        <result property="content"    column="content"    />
        <result property="theOrder"    column="the_order"    />
        <collection property="children" select="getChildren" column="objective_id" ofType="(...).OKRAlignTreeNode"/>
    </resultMap>
    
    <select id="getTree" parameterType="Map"  resultMap="TreeNodeResult">
        select
            objective_id,content,the_order
        from okr_objective oo
        where oo.objective_id = #{id}
        order by the_order
    </select>
    <select id="getChildren" resultMap="TreeNodeResult">
            select objective_id,content,the_order
            from
            (select objective_id from okr_aline where parent_ids = #{objective_id} ) a
            left join okr_objective oo on a.objective_id = oo.objective_id
            order by b.the_order
    </select>
    
    1. mapper文件
    public interface OKRAlignExportMapper {
        TreeNode getTree(Long objectiveId);
    }
    
    1. 查询结果

    5NVyiF.png

    树结构导出到Excel

    关于树形结构数据导出,我参考这篇博客,并针对OKR的特点做了修改。

    Java 树形结构数据生成导出excel文件

    OKR对齐视图数据结构的特点是:

    • 1.以本人的目标为中心,向左右两侧发散。
    • 2.左侧是自己对齐的目标,以及对齐目标再次对齐的目标,递归到顶。
    • 3.右侧是向自己对齐的目标,递归到底。

    关于OKR对齐视图这种数据结构的导出,我们下篇博客会把完整的代码放上来,并分析一下。这里说一下导出这种树形结构数据的主要步骤:

    • 1.计算每条数据的行列坐标,这里采用递归的算法,最终可以计算出父级节点需要合并的行数,以及Excel文件的最大列数。
    • 2.根据行列坐标递归输出每条数据的值到Excel单元格。

    Mybatis一级缓存导致的问题

    首先我们来了解一下Mybatis一级缓存:

    Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

    mybatis一级缓存二级缓存

    由于Mybatis的缓存机制,导致在出现重复的叶子节点时,虽然树结构正常构建,但是指向的是同一个java对象。因为是使用的Mybatis的递归查询,因此确认整个查询在一个SqlSession中执行完成,肯定是一级缓存导致的。这样会造成的后果,就是无法设置重复叶子节点的正确位置,因为指向同一个java对象,后遍历到的节点设置会覆盖前面的节点设置。

    解决方案

    既然确定是一级缓存导致的,那关闭或者清除一级缓存就行了吧。因为是框架的递归查询,因此无法
    调用SqlSession的修改、添加、删除、commit(),close等清空一级缓存。那怎么办呢,笨办法了:

    既然树的结构关系时正确的,只是重复节点指向了同一个java对象,那就遍历重建对象吧

    /**
     * 深度拷贝树结构
     * @param node
     * @return
     */
    private static OKRAlignTreeNode deepCopyTree(OKRAlignTreeNode node){
        OKRAlignTreeNode newNode = node.clone();
        List<OKRAlignTreeNode> children = node.getChildren();
        if(children!=null&&children.size()>0){
            List<OKRAlignTreeNode> newChildren = new LinkedList<>();
            for (OKRAlignTreeNode child:children){
                if(child!=null){
                    OKRAlignTreeNode newChild = deepCopyTree(child);
                    newChildren.add(newChild);
                }
            }
            newNode.setChildren(newChildren);
        }
        return newNode;
    }
    
  • 相关阅读:
    BigPipe_高性能流水线页面技术
    高并发大流量网站 10 个解决方法
    崇高不是比惨
    utf-8无bom格式编码
    go.php
    微信+QQ跳转
    java 设计模式-单例
    HTML连载88-今天把努比亚界面仿真写完了(完结连载)
    Android连载10-动态添加页面、创建一个新闻app
    JavaScript连载9-三目运算符、综合复习
  • 原文地址:https://www.cnblogs.com/zhangdk/p/okrtree.html
Copyright © 2011-2022 走看看