數據導入功能實現心得


          剛接到這個需求感覺很簡單,看大致意思主要是,從Excel中讀取數據並寫入到數據庫中,唯一特殊之處是有一列大字段(超過4000個字符,在數據庫中需要用CLOB類型存儲)需特殊處理。想了下把代碼寫好了。開始測試發現,導入一條數據需要8秒左右,按這速度導20萬數據的話,不敢往下想了,於是想着代碼調優,優化以後速度變成了一分鐘導入一千多條。以此爲背景,分享下修改過程中的心得。

        過程中遇到很多問題,但都順利解決,下面羅列下主要遇到的問題以及有效解決方式。

問題1:如何獲取合併單元格的值?

解決方式:

public static void InsertData(String sjly, File excelFile, String tableName) {
   Workbook rwb = null;
   //創建輸入流
   InputStream stream = new FileInputStream(excelFile);
   //獲取Excel文件對象
   rwb = Workbook.getWorkbook(stream);
   //選擇第一個工作表
   Sheet sheet1 = rwb.getSheet(0);
   String str = null;
      for (int j = 1; j < sheet1.getRows(); j++) {
      for (int k = 0; k < sheet1.getColumns(); k++) {
     str = sheet1.getCell(k, j).getContents();
     Range[] ranges = sheet1.getMergedCells();//合併單元格範圍
     for (Range r : ranges) {
      if (j > r.getTopLeft().getRow()&& j <= r.getBottomRight().getRow() && k == r.getTopLeft().getColumn()) {
       str = sheet1.getCell(r.getTopLeft().getColumn(), r.getTopLeft().getRow()).getContents();
      }
     }
}
}


問題2:獲取當前時間比系統時間晚8個小時

解決方法:

在獲取當前時間的代碼前設置時區,代碼如下所示:

TimeZone tz =TimeZone.getTimeZone("Asia/Shanghai");
  TimeZone.setDefault(tz);
  String Nowtime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());


問題3:CLOB類型字段處理

解決方式:由於Excel中部分數據列超過4000字符,varchar2不夠用,因此可使用clob數據類型對這些大數據量的數據列進行存儲。而LOB數據不能像其它類型數據一樣直接插入(INSERT)。插入前必須先插入一個空的LOB對象,CLOB類型的空對象爲EMPTY_CLOB (),之後使用帶“for update”的查詢語句鎖定更新行,繼而將空對象修改爲所要插入的LOB對象。對於clob數據的修改,可在修改該表的其他字段信息時同時將clob字段修改爲EMPTY_CLOB (),然後纔對clob字段單獨修改。

問題4:向CLOB對象中寫入數據

解決方式:

String update_sql = "select GSXX  from " + tableName + " where ID='"+id+"' for update";
   conn.setAutoCommit(false);   
   rs = conn.createStatement().executeQuery(update_sql);  
   if (rs.next()) {   
    /* 取出此CLOB對象 */  
    oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("GSXX");   
    /* 向CLOB對象中寫入數據 */  
    BufferedWriter out = new BufferedWriter(clob .getCharacterOutputStream());   
    try {   
     out.write(impvo.getGSXX().toString());   
     out.flush();   
     out.close();   
       } catch (IOException e) {   
     e.printStackTrace();   
    }   
   }   
   rs.close();   
   conn.commit();   
   conn.setAutoCommit(true);


這樣寫單條的時候問題不大,當有大數據時會報:ORA-00604: 遞歸 SQL 級別 1 出現錯誤,ORA-01000: 超出打開遊標的最大數的錯誤,

解決方式:將  rs = conn.createStatement().executeQuery(update_sql);  
改爲:stmt = conn.createStatement();
            rs = stmt.executeQuery(update_sql);

並在關閉rs對象時同時關閉stmt 對象即可解決。

         解決完以上問題,最大的問題是效率,調試代碼發現比較慢的地方,第一個就是創建數據庫鏈接:Connection conn = DBUtil.getOracleConnection();耗時大概3秒,檢查代碼發現,這一段代碼竟然是在一個For循環裏,尷尬,於是把這一段放在For循環外面,然後當參數傳遞。這個修改以後稍微快了兩三秒,但還是很慢;於是把單條處理做成批量處理。速度是1分鐘大概一千多條。大功告成。

代碼下載鏈接:數據導入實現參考源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章