編程中踩過的坑

從今天開始在這紀錄我編程過程當中所遇到的坑,這些坑是徹底能夠避免的,分享出來但願你們不要再入坑,你們也能夠分享出踩過的坑sql

一、生成文件的坑(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)

在寫文件的時候每每會有一些特殊的處理,好比往第一行插入統計的數據,這時候就要用到RandomAccessFile類的相關方法,然而這裏面也是有不少坑的,先看下面這段代碼。app

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了。如是我也只能在建立文件的時候先在文件裏寫入一行空格,而後後面再調用上面的方法。dom

/**
     * 寫入本地臨時文件第一行佔位符
     * @param file
     */
    protected void writeTempFirstLine(File file){
        try {
            FileUtils.writeStringToFile(file,"                             ".concat(IOUtils.LINE_SEPARATOR));
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(">>>>>>>>>本地臨時文件第一行佔位符號數據寫入異常", e);

        }
    }

方法着實的有點low啊,不過仍是能解決這個問題的,若是第一行臨時佔位的數據有其它需求能夠重寫上面的方法,你們有更好的方法也但願能提出來。ui

三、分頁查詢的坑

在實際的開發過程當中會常常用到分頁查詢,尤爲是數據量大的狀況下,根據起始ID加上pageSize;而後用一個while(true){}的循環去處理中間的邏輯,這個中會用到break,continue以及return,稍不注意就會遇到相似於死循環等一些邏輯問題。那麼咱們必定要注意哪些點呢?
一、當咱們在循環中用到return的時候必定要問下本身:後面的處理步驟是否依賴循環處理的數據!
二、循環的結束條件是否能知足要求!
三、query.setLimit(size) 每次循環查詢的pageSize最好放在循環內部,尤爲調用的是同一個應用的方法的時候。
下面給出通用的僞代碼:code

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());
        }

步驟比較簡單,不過用得頻率高,因此尤爲須要注意!開發

四、SQL中的坑

(1)假設有表 user,有金額相關的字段:本金 amount,收益 earning,真實本金:real_amount,真實收益:real_earning,如今須要將real_amount + real_earning - ((amount + earning)的差值加到對應的real_earning,real_amount。看似很完美,實際的結果是real_earning的值先修改了,後面參與運算的值已是修改後的值了,這個sql直接讓我吐血了,也背了一個很大的鍋。get

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
相關文章
相關標籤/搜索