使用mysql存储动态字段策略&&对于两个集合之间的数据封装问题

一、使用mysql存储动态字段策略

字段表结构

在这里插入图片描述

数据表结构 专家表

在这里插入图片描述数据表通过"expert_uuid"来区分多条数据是否是一个用户.

"zd_id"字段对应于字段表的"id"字段,也就是说这样一条用户信息可以有多条数据每条数据对应于一条字段表中的数据这样就实现了用mysql存储动态字段了.

对于数据的返回,列表的数据一般不会是动态的,而是固定不可变的,所以就可以设计一个VO对象来专门把对应每条用户数据封装进一个VO即可;对于查询详细则把一个用户的所有数据传给前端即可

优点:这样设计可以满足大部分业务需求
缺点:会造成数据量很大影响效率,数据的处理非常麻烦;建议动态的字段使用非关系型数据库,如mongodb

二、对于两个集合之间的数据封装问题

专家评审表

在这里插入图片描述

专家库表

在这里插入图片描述

上面说了查询专家库列表需要设计一个VO对象来把一个用户的多条数据封装进一个对象,所以在此可以吧专家库表直接当做是一条数据就是一个用户,那么专家库和专家评审两张表就成了一对一的关系,关联字段专家库“expert_uuid”和专家评审“cract_uuid”。

现在问题来了现在查询出来的专家库列表需要专家评审表里面的opinion的值,因为逻辑上的原因,在专家库里面加这个字段是不合逻辑的,所以我考虑了直接再专家库的VO对象中加这个属性,那么又出现了一个问题,数据改怎么封装进来呢?
在这里插入图片描述

有两种不太推荐的方法,第一种就是先拿到专家库里面的数据集合,然后遍历这个集合,通过关联字段去查询另一个表里面对应的数据来实现封装,但是这样会造成多次的去访问数据库,很明显的影响性能
下面展示一些 。

 /**
     * 不推荐方案1
     *
     * @param projectId
     * @return
     */
    @Override
    public List<DigitExpertDatabaseVo> getZjListByProjectIdDemo1(Long projectId) {
        //获取专家数据
        List<DigitExpertDatabaseVo> dataList = digitExpertDatabaseService.selectDigitExpertDatabaseList(null).get("list");
        //遍历专家数据
        for (DigitExpertDatabaseVo digitExpertDatabaseVo : dataList) {
            //通过专家uuid查询对应的专家评审数据并封装数据
            DigitZjpsZj digitZjpsZj = digitZjpsZjMapper.selectDigitZjpsZjByUuid(digitExpertDatabaseVo.getExpertUuid());
            if (digitZjpsZj == null) {
                continue;
            }
            digitExpertDatabaseVo.setIsAgree(digitZjpsZj.getOpinion());
        }
        return dataList;
    }

第二种是把两边的数据一次性都拿到集合,然后通过遍历专家库集合拿到其中一个专家的uuid,然后再通过这个uuid去遍历专家评审表去找到对应数据并进行封装,但是这样就会出现双层for循环,在开发中,也是要尽量避免使用双层for的,比如说两个集合里面都有100条数据,最后就可能循环10000次!

/**
     * 不推荐方案2
     *
     * @param projectId
     * @return
     */
    @Override
    public List<DigitExpertDatabaseVo> getZjListByProjectIdDemo2(Long projectId) {
        //获取专家数据
        List<DigitExpertDatabaseVo> dataList = digitExpertDatabaseService.selectDigitExpertDatabaseList(null).get("list");
        //获取专家评审数据
        List<DigitZjpsZj> digitZjpsZjList = digitZjpsZjMapper.selectDigitZjpsZjByProjectId(projectId);
        //遍历专家数据
        for (DigitExpertDatabaseVo digitExpertDatabaseVo : dataList) {
            //遍历专家评审数据
            for (DigitZjpsZj digitZjpsZj : digitZjpsZjList) {
                if (digitExpertDatabaseVo.getExpertUuid().equals(digitZjpsZj.getCractUuid())) {
                    digitExpertDatabaseVo.setIsAgree(digitZjpsZj.getOpinion());
                }
            }
        }
        return dataList;
    }

所以上面两种方法并不推荐使用,那么我就想可不可以像map集合一样我直接get对应的uuid就可以拿到对应的实体类呢,有了思路我们就要尝试。

经过不停地碰壁,终于找到了两种比较推荐的方案:
推荐方案一:
如果只需要一个字段的封装,我们可以让map的key作为uuid,对应的值为value,也就是这样Map<String,Integer>,但是经过测试这样是不行的,因为sql语句最起码要返回两个字段
在这里插入图片描述
经过多次测试得到的结果是,接收数据的类型应该是map嵌套map也就是Map<String,Map<String,Integer>>
在这里插入图片描述这样接收数据,外层map的key就是对应的uuid,内层的key就是对应的字段名,value就是字段值.
map数据展示
在这里插入图片描述

业务代码:

 /**
     * 推荐方案1
     *
     * @param projectId
     * @return
     */
    @Override
    public List<DigitExpertDatabaseVo> getZjListByProjectIdDemo5(Long projectId) {
        //获取专家评审数据
        Map<String, Map<String, Integer>> zjpsMap = digitZjpsZjMapper.selectDigitZjpsZjMapByProjectIdTest(projectId);
        if (StringUtils.isEmpty(zjpsMap)) {
            return null;
        }
        //获取专家库数据
        List<DigitExpertDatabaseVo> dataList = digitExpertDatabaseService.selectDigitExpertDatabaseList(null).get("list");
        if (StringUtils.isEmpty(dataList)) {
            return null;
        }
        //封装数据
        for (DigitExpertDatabaseVo digitExpertDatabaseVo : dataList) {
        	//拿到内层map
            Map<String, Integer> map = zjpsMap.get(digitExpertDatabaseVo.getExpertUuid());
            if (StringUtils.isEmpty(map)) {
                continue;
            }
            //获取到需要的值
            Integer opinion = map.get("opinion");
            digitExpertDatabaseVo.setIsAgree(Convert.toLong(opinion));
        }
        return dataList;
    }

推荐方案2:
如果我们要封装的不值一个字段,而是多个甚至是整个实体,那样的话我们的map的value值就必须得包含多个属性的值,当然使用方案1也是完全适用的.
我们把xml中的返回值类型改为手动映射resultMap=“DigitZjpsZjResult”
在这里插入图片描述
手动的去写字段和表之间的映射
在这里插入图片描述mapper中的方法
在这里插入图片描述
业务代码

 /**
     * 推荐方案2
     *
     * @param projectId
     * @return
     */
    @Override
    public List<DigitExpertDatabaseVo> getZjListByProjectIdDemo8(Long projectId) {
        //获取专家评审数据
        Map<String, DigitZjpsZj> zjpsMap = digitZjpsZjMapper.selectDigitZjpsZjMapByProjectId(projectId);
        if (StringUtils.isEmpty(zjpsMap)) {
            return null;
        }
        //获取专家库数据
        List<DigitExpertDatabaseVo> dataList = digitExpertDatabaseService.selectDigitExpertDatabaseList(null).get("list");
        if (StringUtils.isEmpty(dataList)) {
            return null;
        }
        //封装数据
        for (DigitExpertDatabaseVo digitExpertDatabaseVo : dataList) {
            //直接获得了所有字段数据
            DigitZjpsZj digitZjpsZj = zjpsMap.get(digitExpertDatabaseVo.getExpertUuid());
            if (StringUtils.isNull(digitZjpsZj)) {
                continue;
            }
            Long opinion = digitZjpsZj.getOpinion();
            digitExpertDatabaseVo.setIsAgree(opinion);
        }
        return dataList;
    }

谢谢大家参考,本人刚开始正式做开发,所以方法可能不是很好,但是基本满足了现在的需求,如果有更好的方法,希望大佬指点!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐