高效快速导入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;
时间: 2024-10-09 16:37:08

高效快速导入EXCEL数据的相关文章

Oracle导入excel数据快速方法

Oracle导入excel数据快速方法 使用PLSQL  Developer工具,这个可是大名鼎鼎的Oracle  DBA最常使用的工具.    在单个文件不大的情况下(少于100000行),并且目的表结构已经存在的情况下——对于excel而言肯定不会超过了,因为excel文件的最大行为65536——  可以全选数据复制,然后用PLSQL  Developer工具.    1  在PLSQL  Developer的sql  window里输入select  *  from  test  for 

SQL Server服务器上需要导入Excel数据的必要条件

SQL Server服务器上需要导入Excel数据,必须安装2007 Office system 驱动程序:数据连接组件,或者Access2010的数据库引擎可再发行程序包,这样就不必在服务器上装Excel了.

asp.net采用OLEDB方式导入Excel数据时提示:未在本地计算机上注册&quot;Microsoft.Jet.OLEDB.4.0&quot; 提供程序&quot;

asp.net采用OLEDB方式导入Excel数据时提示:未在本地计算机上注册"Microsoft.Jet.OLEDB.4.0" 提供程序" 笔者在项目中做做了一个从Excel表格中导入数据的模块.大体上asp.net项目中导入Excel大体分成三类: 1)采用c#内置方案System.Data.OleDb(限制较小, 通用) 2)采用Excel的COM组件(会有版本问题) 3)采用伪Excel文件.即使用文本流的方式根据需求自己定义数据格式.同时在服务端进行反格式化 笔者采

C#导入Excel数据

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data; using System.Data.OleDb; using test.App_Code; using System.Text.RegularExpressions; using Sy

(转)PLSQL Developer导入Excel数据

场景:近来在做加班记录的统计,主要是统计Excel表格中的时间,因为我对于Excel表格的操作不是很熟悉,所以就想到把表格中的数据导入到数据库中,通过脚本语言来统计,就很方便了!但是目前来看,我还没有完成最终统计的目的,只是将Excel中的数据导入到了数据库中了,所以未完待续! 最近处理将Excel数据导入Oracle的工作比较多.之前都是采用Sqlldr命令行导入的方式处理.每次导入不同格式的Excel表数据,都需要先把Excel文件由“.xls”格式转换为“.csv”格式,再手工根据Exce

windows命令行下导入excel数据到SQLite数据库

1.转换文件格式,防止中文乱码:将excel保存成"CSV(逗号分隔)(*.csv)"格式,关闭文件,用记事本打开刚才保存的.csv文件,然后另存为UTF-8格式文本.需要注意的是,经过这样的转换,数字也全变成文本了. 2.通过adb shell(adb.exe存放在android开发软件安装文件夹中,如 F:\Develope\Tools\adt-bundle-windows-x86\sdk\platform-tools\)更改sqlite数据库的使用权限.运行adb之前要先打开AV

结合bootstrap fileinput插件和Bootstrap-table表格插件,实现文件上传、预览、提交的导入Excel数据操作流程

1.bootstrap-fileinpu的简单介绍 在前面的随笔,我介绍了Bootstrap-table表格插件的具体项目应用过程,本篇随笔介绍另外一个Bootstrap FieInput插件的使用,整合两者可以实现我们常规的Web数据导入操作,导入数据操作过程包括有上传文件,预览数据,选择并提交记录等一系列操作. 关于这个插件,我在早期随笔<Bootstrap文件上传插件File Input的使用>也做了一次介绍,这是一个增强的 HTML5 文件输入控件,是一个 Bootstrap 3.x

导入Excel数据至数据库——思路整理

说明 背景: 导入Excel数据到数据库成为目前项目中很常用的技术,整理以前的实现发现:在原来系统中的导入,没有实现方法复用,如果要实现某一处数据的导入,需要将原来的代码复制过去.修修改改,实现过程较为复杂,实现类似的功能需要对原来的代码重新梳理,结合业务修改代码. 为了让每次相同的功能都不需要重复的开发,我们需要实现一种能够得到复用的程序功能. 目的: 如图所示 我们需要将Excel中的数据记录插入到DB的表中,如何实现? 转换 将Excel转换为List 将Excel转换为DataTable

尝试OUTFIle、INFILE快速导入导出数据

尝试OUTFIle.INFILE快速导入导出数据 应用场景: 前几天开发突然有这么一个需求,想导一份200多G的mysql数据出来到另一台机器上,而且时间有点赶,第一时间就想要使用Xtrabackup来全备与增备.但想到之前使用Xtrabackup来备份恢复的时候出现了各种坑,就问了下同事有什么好建议来快速导出导入数据,后来知道了可以使用select into outfile导出表数据,就冒着尝试一下的心里去弄了一下,得到的结果是惊人的,个人感觉速度要比Xtrabackup快很多. 使用sele