1. 程式人生 > >JDBC寫資料到檔案中再Copy到postgresql中

JDBC寫資料到檔案中再Copy到postgresql中

經過測試,大概寫入12萬條資料2秒+左右。

程式碼如下:

package com.nsfocus.bsaips.main;
import com.alibaba.fastjson.JSONObject;
import com.nsfocus.bsaips.util.RemoteDBUtil;
import org.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;
import java.sql.*;
import java.util.ArrayList;
import java.io.*;
import java.util.List;
import java.util.UUID;

public class Test {
    public String writeFile(List<JSONObject> list){
        FileWriter out = null;
        String filePath = "/tmp/"+UUID.randomUUID();

        try{
            out = new FileWriter(new File(filePath));
            for(int i=0;i<list.size();i++){
                Object[] objs = list.get(i).values().toArray();
                for(int j=0;j<objs.length;j++){
                    if(objs[j] == null){
                        out.write("null");
                    }else{
                        out.write(String.valueOf(objs[j]));
                    }
                    if(j != objs.length - 1){
                        out.write(",");
                    }
                }
                if(i != list.size() - 1){
                    out.write("\n");
                }
            }
            out.flush();
        }catch(Exception ex){
            ex.printStackTrace();
        }finally{
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return filePath;
    }

    public void copyTest(String tablename,List<JSONObject> list){
        Connection conn = null;
        CopyManager copyManager = null;
        FileReader reader = null;

        try{
            long starttime = System.currentTimeMillis();
            String filePath = writeFile(list);

            conn = RemoteDBUtil.getInstance("ip",5432,"dbname","username","password").getConnection();
            copyManager = new CopyManager((BaseConnection)conn);
            reader = new FileReader(new File(filePath));
            copyManager.copyIn("copy "+tablename+" from stdin delimiter as ',' NULL as 'null'",reader);
            long endtime = System.currentTimeMillis();

            System.out.println(endtime-starttime);
        }catch(Exception ex){
            ex.printStackTrace();
        }finally{
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args){
        List<JSONObject> list = new ArrayList<JSONObject>();
        for(int i=0;i<120000;i++){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id",i);
            jsonObject.put("testname","aaaa");
            list.add(jsonObject);
        }

        new Test().copyTest("copytest", list);
    }
}

然後,請記住COPY完成後一定要刪除檔案。

刪除檔案的程式碼:

File file = new File(filePath);
if(file.exists()){
    file.delete();
}

另外,再記錄一個小插曲:

居然有張表據說最多每次插入3000條資料(100*30),要不然時間就會變長而且磁碟IO很高。我的眼鏡都快掉到地上摔碎了,一度懷疑自己進入了平行宇宙。

後來一看,表上有個主鍵約束,而寫入的資料中是包含主鍵這個欄位的,也就是每條寫入的資料資料庫都需要檢測唯一性。而當時,表中的資料已經600w+條了。不用會懷疑入庫速度為啥如此之慢了。

而主鍵欄位本身使用UUID生成的(網絡卡+毫米級時間戳+隨機數)絕對保證唯一的,所以根本不需要資料庫來保證唯一性。把約束去掉,入庫速度就坐上飛機了。