zoukankan      html  css  js  c++  java
  • 编程中踩过的坑

    从今天开始在这纪录我编程过程中所遇到的坑,这些坑是完全可以避免的,分享出来希望大家不要再入坑,大家也可以分享出踩过的坑

    1、生成文件的坑(1)

    编程过程中生成文件是一个很常见的需求,为了图方便我使用了反射去获取所有的字段,再一次写入文件中,我以为这是个很巧的方式,结果后来发现BUG了,花了很长的时间去找到这个根源所在,话不多说先贴出我的代码

     protected static String getLineString(Object obj) throws IllegalAccessException, IOException{
            StringBuilder sb = new StringBuilder();
            Field[] fields = obj.getClass().getDeclaredFields();
            boolean access = false;
            for(int i = 1; i < fields.length; i++){
                access = fields[i].isAccessible();
                if(!access){
                    fields[i].setAccessible(true);
                }
                if(fields[i].get(obj) == null || fields[i].get(obj).equals("null")){//null不显示
                }else {
                    sb.append(String.valueOf(fields[i].get(obj)));
                }
                if(i != fields.length -1) {//最后一行不加
                    sb.append(SEPARATOR);
                }
                if(!access){
                    fields[i].setAccessible(false);
                }
            }
    
            return sb.toString();
        }
    
    

    后来我去读文件的时候发现读一个字段一直读得都不对,这可害苦了我,后来我才想起来是不是我生成文件的地方有问题,把实体类和数据库字段顺序一比对,果然,其中有几个字段和数据库字段的顺序不一样。下次千万不能因为省事去用反射了,还是一个个字段的写吧,而且这样也有好处,就是后来加字段和改字段了都不会受到影响,不然另外一个同事某天修改了这块你不知道,那问题可就大了。

    2、生成文件的坑(2)

    在写文件的时候往往会有一些特殊的处理,比如往第一行插入统计的数据,这时候就要用到RandomAccessFile类的相关方法,然而这里面也是有很多坑的,先看下面这段代码。

        protected void writeFirstLine(String firstLine,  String filePath){
            RandomAccessFile raf = null;
            try {
                raf = new RandomAccessFile(filePath, "rw");
                raf.seek(0);
                raf.write(firstLine.getBytes("UTF-8"));
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    

    在第一行的起始位置是插入了我们想要的数据了,然而其它的数据就会被覆盖,这时候如何办是好呢,将整个文件读取出来然后在前面插入第一行数据,然后再写入文件?遇到特别大的文件的时候这种方法就GG了。如是我也只能在创建文件的时候先在文件里写入一行空格,然后后面再调用上面的方法。

        /**
         * 写入本地临时文件第一行占位符
         * @param file
         */
        protected void writeTempFirstLine(File file){
            try {
                FileUtils.writeStringToFile(file,"                             ".concat(IOUtils.LINE_SEPARATOR));
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(">>>>>>>>>本地临时文件第一行占位符号数据写入异常", e);
    
            }
        }
    

    方法着实的有点low啊,不过还是能解决这个问题的,如果第一行临时占位的数据有其它需求可以重写上面的方法,大家有更好的方法也希望能提出来。

    3、分页查询的坑

    在实际的开发过程中会经常用到分页查询,尤其是数据量大的情况下,根据起始ID加上pageSize;然后用一个while(true){}的循环去处理中间的逻辑,这个中会用到break,continue以及return,稍不注意就会遇到类似于死循环等一些逻辑问题。那么我们一定要注意哪些点呢?
    1、当我们在循环中用到return的时候一定要问下自己:后面的处理步骤是否依赖循环处理的数据!
    2、循环的结束条件是否能满足要求!
    3、query.setLimit(size) 每次循环查询的pageSize最好放在循环内部,尤其调用的是同一个应用的方法的时候。
    下面给出通用的伪代码:

            QueryParam query = new QueryParam();
            query.setOffset(0);
            int pageSize = 2000;
            //必要的时候要加上orderBy,否则会漏查数据
            query.setOrderBy(new OrderBy("id",OrderBy.ASC));
            while (true){
                query.setLimit(size);
                Result<List<EntityDTO>> listResult = QueryFacade.query(query);
                if (!listResult.isSuccess() || listResult.getData() == null){
                    logger.warn(">>>>>>>>>>>>查询投失败");
                }
                if (CollectionUtils.isEmpty(listResult.getData())){
                    break;
                }
                List<EntityDTO> data = listResult.getData();
                for (EntityDTO feeDTO : data){
                   //处理一些业务逻辑
                }      
                int currentSize = data.size();
                if (currentSize < size) {
                    break;
                }
                query.setGtId(data.get(data.size()-1).getId());
            }
    

    步骤比较简单,不过用得频率高,所以尤其需要注意!

    4、SQL中的坑

    (1)假设有表 user,有金额相关的字段:本金 amount,收益 earning,真实本金:real_amount,真实收益:real_earning,现在需要将real_amount + real_earning - ((amount + earning)的差值加到对应的real_earning,real_amount。看似很完美,实际的结果是real_earning的值先修改了,后面参与运算的值已经是修改后的值了,这个sql直接让我吐血了,也背了一个很大的锅。

        UPDATE USER
        SET real_earning = real_earning + (
    	real_amount + real_earning - ((amount + earning)),
    	real_amount = real_amount + (
    		real_amount + real_earning - ((amount + earning))
    		WHERE
    			end_benefit_date >= '2018-10-19'
    		AND end_benefit_date <= '2018-10-21'
    		AND settle_status IN (0, 1)
    		AND (
    			real_amount + real_earning - ((amount + earning)) > 0
    
  • 相关阅读:
    阿里fastjson工具类
    poi导出excel2007版本
    java 利用poi 实现excel合并单元格后出现边框有的消失的解决方法
    spring整合atomikos实现分布式事务
    彻底理解ThreadLocal
    kubernetes架构和组件
    Promethues实战-简易教程系列
    Celery
    对称加密,非对称加密,证书机制
    Git diff
  • 原文地址:https://www.cnblogs.com/WangHaiMing/p/9451537.html
Copyright © 2011-2022 走看看