关联表多数据的批量insert (批量导入,测试19W条数据用时46秒)

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。

一、业务需求 :作多个批量导入 ,根据业务不同,每条数据导入前作各种验证,

                          导入后提示验证失败的所有数据和原因。

 

二、思路: 1. 批量导入用 jdbc 直连数据库 addBatch方法实现 ,不走 Mybatis ,

       2. 数据验证用 SQL 语句实现,不走 Mybatis ,

              3. 创建临时表记录合格数据并导入正式数据库表

                   4. 创建临时表记录验证失败的数据,并最终返回

     5. 由于业务需求批量导入时是要导入到 2 张主外键关联表 ,

              所以一次性获取多个序列值以实现 2 表主外键的一致性。

6.  用 sessionID 区分表名和序列名,实现并发导入时数据无污染 。

 

三、代码:

 

 

 /*** 跳转用户导入页面* @param request* @param session* @return String */@RequestMapping("userInfoImport")public  String userInfoImport(HttpServletRequest request,HttpSession session){return "op/usermgr/userInfoImport";}@RequestMapping("userInfoExcelImport")public  String userInfoExcelImport(HttpServletRequest request,HttpSession session,@RequestParam("excelPath")MultipartFile excelPath){Long start = System.currentTimeMillis();String backUrl = "../usermgr/initQuery.do";String[] excelTop = new String[]{"msisdn","custname","phoneType","creditamount","payType"}; // 表头String tableName = session.getId().substring(0,8);// 定义-修改数据临时表 String updateListTemp ="CREATE TABLE updateListTemp"+tableName+"("+"id integer NOT NULL,"+"msisdn varchar2(12) NOT NULL,"+"custname varchar2(50) NOT NULL,"+"phoneType varchar2(50) NOT NULL,"+"creditamount varchar2(10) NOT NULL,"+"payType varchar2(50) NOT NULL)"+" tablespace ISMP pctfree 60 initrans 1 maxtrans 255 storage (initial 64K) ";String updateTemp_seq ="CREATE SEQUENCE updateTemp_seq"+tableName+""+" INCREMENT BY 1" // 每次加1+" START WITH 1 "  // 从1开始计数+" NOMAXvalue "    // 不设置最大值+" NOCYCLE " 	    // 一直累加,不循环+" CACHE 10 "; 	    // 缓存10个// 定义-新增数据临时表 String insertListTemp ="CREATE TABLE insertListTemp"+tableName+"("+"id integer NOT NULL,"+"msisdn varchar2(12) NOT NULL,"+"custname varchar2(50) NOT NULL,"+"phoneType varchar2(50) NOT NULL,"+"creditamount varchar2(10) NOT NULL,"+"payType varchar2(50) NOT NULL)"+" tablespace ISMP pctfree 60 initrans 1 maxtrans 255 storage (initial 64K) ";String insertTemp_seq ="CREATE SEQUENCE insertTemp_seq"+tableName+""+" INCREMENT BY 1" // 每次加1+" START WITH 1 "  // 从1开始计数+" NOMAXvalue "   // 不设置最大值+" NOCYCLE "	     // 一直累加,不循环+" CACHE 10 "; try {if(excelPath == null){OprResult.SetOprResult(request, "导入用户异常","导入用户失败,请选择要导入的内容 !", backUrl,OprResult.FAILURE);return "/op/oprResult";}// 解析得到的用户表集合List<List<Object>> usrlist = ImportExcelUtil.getExcelList(excelPath.getInputStream(),excelTop);if(usrlist == null){OprResult.SetOprResult(request, "导入用户异常", "导入用户信息,数据表格不能有空值 !", backUrl,OprResult.FAILURE);return "/op/oprResult";}// 验证电话、宽带账号List<String> failMsisdnList = new ArrayList<String>();List<String> msiddn = new ArrayList<String>();for(int y =0; y<usrlist.size(); y++){if(String.valueOf(usrlist.get(y).get(2).toString()).equals("电话号码")){ // 验证电话号码if(!ValidateUtils.isMobile(usrlist.get(y).get(0).toString())){failMsisdnList.add(usrlist.get(y).get(0).toString());usrlist.remove(usrlist.get(y));y--;}}else{if(ValidateDhmp.validateUserMsisdn(usrlist.get(y).get(0).toString())){ // 验证宽带账号failMsisdnList.add(usrlist.get(y).get(0).toString());usrlist.remove(usrlist.get(y));y--;}}}int failsize = failMsisdnList.size();// 去重for(int y =0; y<usrlist.size(); y++){if(y<1){msiddn.add(usrlist.get(y).get(0).toString());}else{if(msiddn.contains(usrlist.get(y).get(0).toString())){usrlist.remove(usrlist.get(y));y--;}else{msiddn.add(usrlist.get(y).get(0).toString());}}}// 创建临时表和序列 -正确数据表、问题数据表BatchInsert.goSql(updateListTemp); BatchInsert.goSql(updateTemp_seq); BatchInsert.goSql(insertListTemp); BatchInsert.goSql(insertTemp_seq); // 导入sql:String insertSql ="insert into insertListTemp"+tableName+" values(updateTemp_seq"+tableName+".nextval,?,?,?,?,?)";BatchInsert.exeBatch(insertSql , usrlist); // 批量导入到新增数据表// 插入问题数据(用户已存在)-sqlinsertSql ="insert into updateListTemp"+tableName+" select updateTemp_seq"+tableName+".nextval,"+"temp.msisdn,temp.custname,temp.phoneType,temp.creditamount,temp.payType"+" from insertListTemp"+tableName+" temp where temp.msisdn in (select msisdn from usr_end_user )";BatchInsert.goSql(insertSql); // 删除问题数据(用户已存在)-sqlString deleteErrorSql ="delete from insertListTemp"+tableName+" where msisdn in (select msisdn from usr_end_user )";BatchInsert.goSql(deleteErrorSql);// 只修改数据String[] col = new String[] {"id","msisdn","custname","phoneType","creditamount","payType"};List<List<Object>> failList = BatchInsert.selectToList("select * from updateListTemp"+tableName,col);failsize += failList.size();StringBuffer failbuffer = new StringBuffer();failbuffer.append("<br><br>一、请注意保留以下信息,此提示只显示一次  !");failbuffer.append("<br><br>二、失败数据,");if(failList != null && failList.size() > 0){failbuffer.append("<br><br> 账号:"); for(List<Object> fail :failList){failbuffer.append(fail.get(1)+", "); }failbuffer.append("<br><br>原因:用户已经存在,请直接编辑。"); }for(List<Object> fail : failList){fail.remove(0);}usrlist.removeAll(failList); // 求差 if(failMsisdnList != null && failMsisdnList.size() > 0){failbuffer.append("<br><br> 账号:");for(String msisdn :failMsisdnList){ // 电话、宽带账号格式不对failbuffer.append(msisdn+", "); }failbuffer.append("<br><br>原因:电话号码或宽带账号格式不对。"); }String squence ="select USR_CUSTOMER_SEQ.nextval cust_id from (select 1 from all_objects where rownum <= "+usrlist.size()+")";List<String> squenceList = BatchInsert.selectSql(squence);// 拼装customListList<List<Object>> customList  = new ArrayList<List<Object>>(); Long maxCode = (long) 0; String maxCustCode = "";for(int i=0; i< usrlist.size(); i++){List<Object> custom = new ArrayList<Object>();custom.add(squenceList.get(i)); // usr_customer表的序列值custom.add(usrlist.get(i).get(1)); // custnamecustomList.add(custom);if(i<2){maxCustCode = usermgrService.findMaxCustCode();if(maxCustCode!= null && !"".equals(maxCustCode)){maxCode = Long.parseLong(maxCustCode)+1;custom.add(String.valueOf(maxCode));}else{custom.add(String.valueOf("10000000")); // setCustCode}}else{maxCode += 1;custom.add(String.valueOf(maxCode)); // setCustCode}}// 客户表insert Sql:String customerSql ="insert into usr_customer(cust_id,cust_name,cust_code)values(?,?,?)";BatchInsert.exeBatch(customerSql , customList); // 插入客户表// 用户表insert Sql:String userSql ="insert into usr_end_user(user_id,cust_id,msisdn,creditamount,phone_type,user_payment_type,"+"user_stat,user_prvc_code,user_trade_type,is_black,is_active,language,user_level,is_test_user,"+"consume_limit,limit_tips,dayfee,monthfee,is_realname)"+" values(usr_end_user_seq.nextVal, ?,?,?,?,? ,?,?,?,?,? ,?,?,?,?,? ,?,?,?) ";// 拼装userListList<List<Object>> userList  = new ArrayList<List<Object>>(); for(int i=0;i<usrlist.size();i++){List<Object> user = new ArrayList<Object>();user.add(squenceList.get(i)); //cust_iduser.add(usrlist.get(i).get(0));//msisdnuser.add(String.valueOf(usrlist.get(i).get(3))); //creditamountif("电话号码".equals(String.valueOf(usrlist.get(i).get(2)))){user.add("1"); //phone_type}else if("宽带号码".equals(String.valueOf(usrlist.get(i).get(2)))){user.add("3"); //phone_type}if("后付费用户".equals(String.valueOf(usrlist.get(i).get(4)))){user.add("1"); //user_payment_type}else  if("预付费用户".equals(String.valueOf(usrlist.get(i).get(4)))){user.add("2"); //user_payment_type}user.add("1"); //user_statuser.add("08"); //user_prvc_codeuser.add("0"); //user_trade_type-账户行业类型:默认为家庭user.add(0); //is_blackuser.add(0); //is_activeuser.add("01"); //LANGUAGEuser.add("01"); //USER_LEVELuser.add(0); //IS_TEST_USERuser.add("'3|0|0|0|0|0|0|0|0'");//consumeLimituser.add("'0|0|0'");//LIMIT_TIPSuser.add("0"); //DAYFEEuser.add("0"); //MONTHFEEuser.add("1"); //IS_REALNAMEuserList.add(user);}BatchInsert.exeBatch(userSql ,userList); // 正式插入用户表/*try{//日志log(session, UsermgrServiceImpl.class,"exeBatch", "批量新增用户");log(session, UsermgrServiceImpl.class,"exeBatch", "批量新增客户");}catch (Exception e){e.printStackTrace();}*/// 删除临时表String dropSql ="drop table updateListTemp"+tableName;String dropSql2 ="drop sequence updateTemp_seq"+tableName;String dropSql3 ="drop table insertListTemp"+tableName;String dropSql4 ="drop sequence insertTemp_seq"+tableName;BatchInsert.goSql(dropSql);BatchInsert.goSql(dropSql2);BatchInsert.goSql(dropSql3);BatchInsert.goSql(dropSql4);Long end = System.currentTimeMillis();System.out.println();System.out.println("导入用户信息表"+userList.size()+"条数据,总用时==============================:"+ (end-start)/1000+"秒 。");System.out.println();if(failsize > 0){OprResult.SetOprResult(request, "提示信息", "部分用户信息导入失败,如下:"+failbuffer, backUrl, OprResult.FAILURE);}else{OprResult.SetOprResult(request, "提示信息", "用户信息导入成功", backUrl, OprResult.SUCCESS);}} catch (EncryptedDocumentException e) {e.printStackTrace();OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);} catch (InvalidFormatException e) {e.printStackTrace();OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);} catch (IOException e) {e.printStackTrace();OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);} catch (Exception e) {e.printStackTrace();OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);}return "/op/oprResult";}

 

 

 

 

 

 

	/*** 判断是不是合法手机号码* @param mobile* @return*/public static boolean isMobile(String mobile) {Pattern pattern = Pattern.compile("^((13[0-9])|(15[0-9])|(18[0-9]))\\d{8}$");return pattern.matcher(mobile).matches();}

 

 

 

 

 

批量导入、表格解析工具类:

 

package com.mc.common.util;import java.sql.Connection;import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;import com.zznode.ismp.mc.common.MspException;/*** 批量导入工具类* @author JiangYu*/
public class BatchInsert {//    private static String url="jdbc:oracle:thin:@127.0.0.1:9521:orcl";    private static String url = MspConfiguration.getInstance().getParaValue("DBUrl");  // oracle数据库用户名     private static String user = MspConfiguration.getInstance().getParaValue("DBUser");    // oracle数据库密码     private static String password = MspConfiguration.getInstance().getParaValue("DBPassword");    public static Connection conn;    public static PreparedStatement ps;    public static ResultSet rs;    public static Statement st ;  public static Connection getConnection(){ //连接数据库的方法        try {    Class.forName("oracle.jdbc.driver.OracleDriver"); //初始化驱动包         conn = DriverManager.getConnection(url, user, password);    } catch (Exception e) {    e.printStackTrace();    }  return conn;}    public static void main(String[] args) {   getConnection();    if(conn==null){    System.out.println("与oracle数据库连接失败!");    }else{    System.out.println("与oracle数据库连接成功!");   }    } /*** 批量运行sql* @param con* @param sql* @param list*/public static void exeBatch(String sql,List<List<Object>> list) throws Exception{try {StringBuffer sqlbuffer = new StringBuffer();sqlbuffer.append(sql);Connection con = getConnection();con.setAutoCommit(false);// 关闭事务自动提交final int batchSize = 1000; // 每满1000条数据运行一次int count = 0;Long startTime = System.currentTimeMillis();PreparedStatement pst = (PreparedStatement) con.prepareStatement(String.valueOf(sql));if(list != null && list.size() > 0){for (int i = 0; i < list.size(); i++) {for(int x =0;x<list.get(i).size();x++){pst.setObject(x+1,list.get(i).get(x));}pst.addBatch();// 把一个SQL命令加入命令列表if(++count % batchSize == 0 ){pst.executeBatch();count = 0;}}}pst.executeBatch();con.commit();pst.close();con.close();Long endTime = System.currentTimeMillis();System.out.println("单纯inserrt用时:" + (endTime - startTime));} catch (Exception e) {e.printStackTrace();throw new MspException("网络不畅,请刷新页面后重试 !");}} // 解析数据表public static List<List<Object>> selectToList(String sql,String[] col){Connection conn = null;//定义为空值Statement stmt = null;ResultSet rs = null;conn = getConnection();List<Object> list = null;List<List<Object>> resultList = new ArrayList<List<Object>>(); try {stmt = conn.createStatement();//创建一个Statement语句对象rs = stmt.executeQuery(sql);//执行sql语句while(rs.next()){list = new ArrayList<Object>();for(int i=0; i< col.length; i++){list.add(rs.getObject(col[i]));}resultList.add(list);}} catch (SQLException e) {e.printStackTrace();}finally{try {conn.close();stmt.cancel();rs.close();}catch (SQLException e) {e.printStackTrace();}}return resultList;}// 执行增、删、改sqlpublic static void goSql(String sql){Connection conn = null;//定义为空值Statement stmt = null;conn = getConnection();try {    stmt = conn.createStatement();    } catch (SQLException e) {    e.printStackTrace();    }    //4、执行语句    try {    stmt.executeUpdate(sql);    } catch (SQLException e) {    e.printStackTrace();    }    //5、关闭操作    try {    stmt.close();    conn.close();    } catch (SQLException e) {    e.printStackTrace();    }}// 单纯查询 public static List<String> selectSql(String sql){Connection conn = null;//定义为空值Statement stmt = null;ResultSet rs = null;conn = getConnection();List<String> list = new ArrayList<String>();try {stmt = conn.createStatement();//创建一个Statement语句对象rs = stmt.executeQuery(sql);//执行sql语句while(rs.next()){list.add(rs.getString("cust_id"));}} catch (SQLException e) {e.printStackTrace();}finally{try {conn.close();stmt.cancel();rs.close();}catch (SQLException e) {e.printStackTrace();}}return list;}}

 

 

 

 

 

说明:此句是为了一次性获取 多个序列值,方便 2 表关联:

String squence ="select USR_CUSTOMER_SEQ.nextval cust_id from (select 1 from all_objects where rownum <= "+usrlist.size()+")";

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/451123.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java已死?九百万程序员说不

Java没死&#xff0c;事实上它拥有足够的能量让你的应用跑起来。那些对Java吹毛求疵人频繁地聚焦在一些小众问题上&#xff0c;总是和其他技术或者语言做些不公平的对比&#xff0c;这些语言并没有像Java一样得到广泛应用及长远的历史。 现在的小孩都能学Java&#xff0c;它在…

Linux SSH远程管理故障如何排查?

SSH远程管理故障排查方案&#xff1a;1、检测两个机器是否畅通两个机器之间是否畅通&#xff0c;查看物理链路是否有问题(网线网卡、IP是否正确)第1步&#xff1a;物理链路是否畅通&#xff0c;比喻为“高速公路是否畅通”ping 排查客户端到服务端的线路问题&#xff0c;ping是…

CSS中position的absolute和relative用法

static: HTML元素的默认定位方式absolute: 将对象从文档流中拖出&#xff0c;使用left&#xff0c;right&#xff0c;top&#xff0c;bottom等属性进行绝对定位。而其层叠通过z-index属性定义。绝对定位的元素的位置相对于最近的已定位父元素&#xff0c;如果元素没有已定位的父…

Spring HttpMessageNotReadableException异常

&#xff08;一&#xff09;现象 我们在进行服务间的rpc调用时&#xff0c;可能会遇到org.springframework.http.converter.HttpMessageNotReadableException异常。 其具体报错如下&#xff1a; {"timestamp": 1456043810789,"status": 400,"error…

解决 -- java 调用webservice 服务端收到参数为null

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 我的客户端和服务端都写的很简单&#xff0c;只是调用服务的时候&#xff0c; 服务端得不到参数&#xff0c;后来发现只改一个地方就可…

fastJson性能测试

测试装备&#xff1a; mac pro 6核12线程 测试代码&#xff1a; &#xff08;1&#xff09;序列化对象&#xff1a; import lombok.Data;Data public class User {int id;String name;int age;String address; } &#xff08;2&#xff09;序列化逻辑&#xff1a; import…

避免流量高峰期CDN问题的10个方法

在视频流媒体中&#xff0c;因平台火爆而出现问题是件好事。至少&#xff0c;这比根本没有观众要好。\\也许你正在使用世界级的CDN&#xff0c;但是&#xff0c;在大型赛事期间&#xff0c;当CDN的服务器和对等点流量变得饱和的时候&#xff0c;一些用户还是无法享受到流畅的体…

Android应用进入爆发期 手机游戏仍是市场重心

近日&#xff0c;91无线发布了《91无线移动应用发展趋势报告&#xff08;Android版&#xff09;》。报告显示&#xff0c;2012年&#xff0c;无论Android移动应用用户下载还是开发者研发均呈爆发态势&#xff0c;手机游戏仍是市场重心所在。同时&#xff0c;Android移动应用下载…

MQTT Client软件-MQTTBox

最近发现了一个连接mqtt broker的软件&#xff1a;MQTTBox。GitHub地址&#xff1a;https://github.com/workswithweb/MQTTBox 官网网站的介绍为&#xff1a;使用MQTTBox增强你的物联网流程 MQTT客户端特性 支持TCP、TLS、Web Sockets和安全的Web Sockets连接MQTT服务器支持各种…

fastJson toJSONString注意点

fastJosn是阿里爸爸推出一款高性能序列化工具&#xff0c;号称最快的json序列化工具。不过好像也就那样&#xff0c;在量比较大的时候优势才会明显。单次序列化时间还是会达到几十毫秒的级别。 Fastjson is a Java library that can be used to convert Java Objects into the…

WebService中文件传输

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 WebService处理传递普通的信息&#xff0c;还可以传输文件&#xff0c;下面介绍WebService是怎么完成文件传输的。 1、 首先编写服务器端…

Django框架-Form组件

一、DjangoForm组件介绍 我们之前在html页面中利用form表单向后端提交数据时&#xff0c;都会写一些获取用户输入的标签并且用form标签把它们包起来。 与此同时我们在好多场景下都需要对用户的输入做校验&#xff0c;比如验证用户是否输入&#xff0c;输入的长度和格式等是否正…

中国经济转型知易行难

摘要&#xff1a;一个亚洲国家正在崛起&#xff0c;出口机器势不可挡&#xff0c;财富快速增长&#xff0c;觉得美国已是过去&#xff0c;自己的时代已经到来。这是2012年的中国&#xff1f;没错———但也是上世纪80年代的日本。 美国《芝加哥论坛报》网站5月20日文章&#xf…

进程和线程的剖析

进程和线程的区别&#xff1f;什么时候用进程&#xff1f;什么时候用线程&#xff1f; 答&#xff1a;首先得知道什么是进程什么是线程&#xff1f; 我的理解是进程是指在系统中正在运行的一个应用程序&#xff1b;程序一旦运行就是进程&#xff0c;或者更专业化来说&#xff1…

解决 java.net.ConnectException: Connection refused: connect 异常

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 一、 我的情况很简单&#xff1a; 只是因为我调用服务端接口方法包名没有写对&#xff0c;应该如下面代码中这样写&#xff1a; call.…

主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间=k的个数)...

取板粗 好东西来的 1.&#xff08;HDOJ2665&#xff09;http://acm.hdu.edu.cn/showproblem.php?pid2665 &#xff08;POJ2104&#xff09;http://poj.org/problem?id2104 &#xff08;POJ2761&#xff09;http://poj.org/problem?id2761 题意&#xff1a;求区间第K大&…

java类内部的变量

类内部的变量分为两部分&#xff1a; 一.类的成员变量 在类内部&#xff0c;变量定义部分&#xff0c;定义的变量。 二.局部变量 在类内方法体中定义的变量和方法中涉及的变量。 成员变量和局部变量的区别&#xff1a; &#xff08;1&#xff09;成员变量在整个类中都有效…

腾讯搜搜退出PC搜索领域:百度搜狗迎来双龙竞争

摘要&#xff1a;据北京商报报道&#xff0c;上周末&#xff0c;腾讯对公司组织架构进行了大规模调整。业内普遍认为&#xff0c;搜搜并入腾讯无线后&#xff0c;这个独立搜索平台将被合并&#xff0c;失去独立性&#xff0c;也将令搜搜官网域名soso.com走向“没落”。据北京商…

facade-pattern外观模式

外观模式&#xff1a; 外观模式是面向对象编程中的重要设计模式。外观类用来掩盖复杂的内部逻辑&#xff0c;为用户提供简洁统一的服务接口。外观类的主要功能如下&#xff1a; 1.通过提供简明的对外API接口&#xff0c;来提高程序的可阅读性和间接性。 2.提供通用的特定功能…

Web Service 客户端,调用服务方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 只是最简单的调用web service 服务&#xff0c;至于要传什么参数全看到业务了。 以下是最简单的调用方式 &#xff1a; package hdmp…