内存分页在项目开发中的使用场景(Java)

内存分页在项目中一般是不推荐使用的,因为效率很低。扫描数据库相关表的所有数据,并全部加载进内存,然后返回需要的数据(可能加载了几万条到内存最终返回5条),极大的消耗了内存。

但在目前负责开发的 狐小E智慧办公 (https://www.hixiaoe.com)平台中,由于某些特殊场景,所以必须通过内存分页的方式解决。

场景1 (批量in查询)

在excel批量导入员工数据时,需要以手机号作为唯一条件校验数据是否已存在,若存在,则以excel中的内容,作为最新记录进行更新,若不存在,则直接更新。

这样的操作就会导致每导入一条就必须查一下数据库看数据是否存在,这样效率很低,优化的方法就是,将要导入的员工手机号全部取出后,用手机号作为条件,去数据库中以 in 的方式查找,这样就可以只与数据库进行一次交互,将数据加载到内存中进行判断。

这时就会有个问题:假如导入的数据有5000条,就表示sql拼接的in条件就有5000个参数,Oracle数据库中IN参数个数不能超过1000,否则会报异常。而Mysql中虽然对in无限制,但是sql默认长度是1M (my.ini 中的max_allowed_packet可调节大小) 虽然可以通过参数调节,但是站在程序层面上可能调节成2M也不够,当调的参数过大,Mysql还会自动设置回默认值,站在程序员的角度上,还是从代码角度解决问题比较稳妥。

这时候就可以使用内存分页了,将内存中的数据根据实际情况分批次访问,比起一次次的循环查数据库,效率肯定高,又不至于出现一次in查询导致sql过长而报错。

场景2(模糊查询加密数据)

在业务实现的过程中,有这么一张表:待离职员工临时表,这个表所涉及的业务就是执行员工离职操作前,若存在待处理事务未提交,则员工信息会被放到这个表中,等待离职事务处理完毕后,即可作真正的离职操作,然后删除这个表对应的数据。表里的数据由于保密性,部分字段(姓名,手机号等) 都做了加密处理。

分析这个表的特点:

数据量比较小(只有类似管理员之类的角色,有未交接完成的事务,才会保存在这张表里)
②页面按条件模糊查询的数据在数据库里都是加密存储的

这种场景下就可以使用内存分页查询到内存中,解密后再和前端传递的搜素词做模糊匹配。数据库其实支持加解密,但目前数据的加密未使用数据库的方式而且,实际使用场景上该表数据量极少,所以一次查询到内存里比数据库执行解密的效率更快。综合考虑用内存分页的方式更合理。

实现方式

利用java8 中 Steam的.skip() 和 limit() 实现

   /**
     * 内存分页
     *
     * @param data     数据
     * @param pageNum  当前页
     * @param pageSize 分页条数
     * @return
     */
   public List<Object> pageOprateInMemory (List<Object> data, Integer pageNum, Integer pageSize) {
        if (CollectionUtils.isEmpty(data)) {
            return null;
        }

        // 根据当前页和分页条数 从总记录数中取数据
        List<Object> temps = data.stream().skip(pageSize * (pageNum - 1)).limit(pageSize)
                             .collect(Collectors.toList());
        return temps;
    }

通过以上内存分页的操作,提升了项目数据查询的效率,减少了数据库对sql限制的错误,对于前端模糊查询少量加密数据也有较好的呈现效果。

 

作者介绍:小文文,狐小E智慧办公 (https://www.hixiaoe.com)开发工程师,专注移动办公软件的SaaS平台建设以及轻应用开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值