zoukankan      html  css  js  c++  java
  • [Java] 高效快速导入EXCEL数据

    需求
    1、高效率的以excel表格的方式导入多条数据。
    2、以身份证号为唯一标识,如果身份证号已存在,则该条数据不导入。

    分析
    刚开始的时候是传统的做法,解析excel数据,获取单个对象,判断身份证是否已存在表中,若没有则插入数据库。否则pass
    结果数据才几百条的时候,导数据都花了10分钟才导入完毕。实在太慢了,看来在程序中做数据的校验很脑残。

    优化
    在插入数据库之前作判断太花时间,没必要。所以最后将数据的处理交给了数据库来做。
    建一个临时表CUST_OBJECT_TEMP,先把所有的数据都用 jdbc batch insert 插入或者分数据段插入,这个过程不做任何的数据校验。
    再搞个存储过程来处理两个表的数据就行了。

    详细代码

    ①  加载上传的xls文件

      private File file; //上传的文件
      private String fileFileName; //文件名称
        
      public File getImage() {
            return image;
      }
      public void setImage(File image) {
            this.image = image;
      }
        
      public String getImageFileName() {
            return imageFileName;
      }
    
      public void setImageFileName(String imageFileName) {
            this.imageFileName = imageFileName;
      }
        
        public String importExcel() throws Exception {
            HttpServletRequest request = ServletActionContext.getRequest();
            String realpath = ServletActionContext.getServletContext().getRealPath("/");
            if (file != null) {
                File savefile = new File(new File(realpath), fileFileName);
                if (!savefile.getParentFile().exists()){
                    savefile.getParentFile().mkdirs();
                }
                FileUtils.copyFile(file, savefile);
                String newName = savefile.getName();
    
                //执行操作
                dao.addAll(realpath+newName);
            }
            return SUCCESS;
        }

    ② 解析excel并调用存储过程

    public void addAll(String url){
        
            //生成一个备用码
            String guid=RandomUtils.myGetNo(9);
            
            //将excel数据转为集合并以100条每次的节奏插入临时表中
            Workbook rwb = null;
            try {
                //InputStream is = new FileInputStream("F:/龙里县贫困户.xls");
                InputStream is = new FileInputStream(url);
                rwb = Workbook.getWorkbook(is);
            } catch (Exception ex) {
                 ex.printStackTrace();
            }
    
            //获取第一张Sheet表
            Sheet rs = (Sheet) rwb.getSheet(0);
            //总行数
            int rsRows = rs.getRows();
            //总列数
            int rsColumns = rs.getColumns();
            Cell c1,c2 = null;
            String strTmp1,strTmp2="";
           
            int no=Integer.parseInt(findMaxId())+10;
            System.out.println("总行数"+rsRows+"总列数"+rsColumns+" "+no);
            try {
                openConn();
                //设置为不自动提交,等凑足100条的时候再批量提交一次
                conn.setAutoCommit(false);
                stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
    
            for(int i=2;i<rsRows;i++){      
                c1 = ((jxl.Sheet) rs).getCell(0, i);
                strTmp1 = c1.getContents();
                c2 = ((jxl.Sheet) rs).getCell(1, i);
                strTmp2 = c2.getContents();
    
                no++;
                
                if(!strTmp1.equals("") && !strTmp3.equals("")){
                    StringBuilder strSql = new StringBuilder();
                    strSql.append(" INSERT INTO CUST_OBJECT_TEMP ");//CUST_OBJECT_TEMP
                    strSql.append(" (CUST_ID,CREDENTIALS,COUNZHENG,GUID) ");
                    strSql.append("    VALUES ");
                    strSql.append(" ('"+no+"','"+strTmp1+"','"+strTmp2+"','"+guid+"') ");
                    
                    try {
                        stmt.execute(strSql.toString());
                        //100条数据提交一次
                        if(i%100==0||i==(rsRows-1)){
                            conn.commit();
                        }
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            try {
                closeAll();
            }catch (Exception e) {
                e.printStackTrace();
            }
            
            //至此所有的excel数据都已经插入到了临时表CUST_OBEJCT_YEMP中了
            //注意:临时表除了有正是表的所有字段,还额外新增了两个字段
            1、IF_INSERT 建表的时候默认为0 表示该数据还没有插入正式表 ,当插入正是表之后,会变为1.
            2、GUID 标识了数据的批次,String guid=RandomUtils.myGetNo(9); 每一次excel导入的数据都同属于一个批次。
            
            
            //调用存储过程
            excelAlladd(guid);
        }

    ③ 调用存储过程定义

    public String excelAlladd(String guid){
    String result
    = "1"; openConn(); try{ CallableStatement c=(CallableStatement) conn.prepareCall("{call PRO_CUST_TABLE(?,?)}"); c.setString(1,guid);//传入批次号guid c.registerOutParameter(2, Types.INTEGER);//设置返回值类型为INT c.execute(); result = c.getString(2); //获取返回值 if("0".equals(result)){ System.out.println("存储过程调用成功"); }else{ System.out.println("存储过程调用失败"); } }catch (Exception e) { System.out.println("调用存储过程"+e); } closeAll(); return result; }

    ④ 存储过程定义

    CREATE OR REPLACE PROCEDURE PRO_CUST_TABLE(V_GUID VARCHAR2,V_RETURN OUT integer)
    IS
    
      V_CNT_1 NUMBER;//定义变量V_CNT_1
      V_RETCODE VARCHAR2(20);//定义结果代码
      V_RETINFO VARCHAR2(20);//定义结果提示
      
      //开始执行存储过程
      BEGIN   
        //取得满足A.IF_INSERT = 0 AND A.GUID = V_GUID(未插入正式表且是同一个批次号)的数据条数 作为 V_CNT_1变量的值
        SELECT COUNT(*) INTO V_CNT_1 FROM CUST_OBJECT_TEMP A WHERE A.IF_INSERT = 0 AND A.GUID = V_GUID;
      
      V_RETURN := 1;//定义返回值为1
      
      //如果有符合插入条件的数据则执行以下操作
      IF V_CNT_1 > 0 THEN
      
        //1)  将满足条件的数据插入到正式表中
        INSERT INTO CUST_OBJECT(
            cust_id,
            CREDENTIALS,
            COUNZHENG
        )
        SELECT  
            CUST_ID,
            CREDENTIALS,
            COUNZHENG
        FROM CUST_OBJECT_TEMP A1
        WHERE IF_INSERT = 0
        AND A1.GUID = V_GUID
        AND NOT EXISTS (
            SELECT 1 FROM CUST_OBJECT A2 WHERE TRIM(A1.CREDENTIALS) = TRIM(A2.CREDENTIALS) 
        );
        COMMIT;
        
        //2) 将满足条件的数据的插入状态更新为已插入IF_INSERT = 1
        UPDATE CUST_OBJECT_TEMP A SET IF_INSERT = 1 WHERE IF_INSERT = 0 AND A.GUID = V_GUID;
        COMMIT;
        
        //3) 将临时表已插入状态的数据插入历史记录表 HIS_CUST_OBJECT 作为追溯的证据
        INSERT INTO HIS_CUST_OBJECT(
            CUST_ID,
            CREDENTIALS,
            COUNZHENG,
            IF_INSERT
        )
        SELECT 
            CUST_ID,
            CREDENTIALS,
            COUNZHENG,
            IF_INSERT
        FROM CUST_OBJECT_TEMP A
        WHERE IF_INSERT = 1 AND A.GUID = V_GUID;
        COMMIT;
        
        //4) 删除临时表的数据
        DELETE FROM CUST_OBJECT_TEMP A WHERE IF_INSERT = 1 AND A.GUID = V_GUID;
        COMMIT;
        
        //如果这些都通过了,设置返回值为0
        V_RETURN := 0;
    END IF;
    
    //捕捉异常
    EXCEPTION
      WHEN OTHERS THEN
        ROLLBACK;
        V_RETCODE := 'FAIL';
        V_RETINFO := SQLERRM;
    end;
  • 相关阅读:
    PAT (Basic Level) Practice 1020 月饼 (25分)
    PAT (Basic Level) Practice 1019 数字黑洞 (20分) (string、int转换+sort排序)
    PAT (Basic Level) Practice 1018 锤子剪刀布 (20分) (三个数比大小)
    PAT (Basic Level) Practice 1017 A除以B (20分) (大数除法+大神简洁20行代码)
    PAT (Basic Level) Practice 1016 部分A+B (15分)
    PAT (Basic Level) Practice 1015 德才论 (25分) (大量IO的节省时间)
    PAT (Basic Level) Practice 1014 福尔摩斯的约会 (20分) (string的find函数中没查找到返回s.npos)
    PAT (Basic Level) Practice (中文) 1013 数素数 (20分)
    XSY1762
    XSY1602
  • 原文地址:https://www.cnblogs.com/avivaye/p/4193752.html
Copyright © 2011-2022 走看看