当前位置:   article > 正文

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

insertbatch 大批量

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

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

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

 

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

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

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

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

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

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

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

 

三、代码:

 

 

  1. /**
  2. * 跳转用户导入页面
  3. * @param request
  4. * @param session
  5. * @return String
  6. */
  7. @RequestMapping("userInfoImport")
  8. public String userInfoImport(HttpServletRequest request,HttpSession session){
  9. return "op/usermgr/userInfoImport";
  10. }
  11. @RequestMapping("userInfoExcelImport")
  12. public String userInfoExcelImport(HttpServletRequest request,HttpSession session,@RequestParam("excelPath")MultipartFile excelPath){
  13. Long start = System.currentTimeMillis();
  14. String backUrl = "../usermgr/initQuery.do";
  15. String[] excelTop = new String[]{"msisdn","custname","phoneType","creditamount","payType"}; // 表头
  16. String tableName = session.getId().substring(0,8);
  17. // 定义-修改数据临时表
  18. String updateListTemp ="CREATE TABLE updateListTemp"+tableName+"("
  19. +"id integer NOT NULL,"
  20. +"msisdn varchar2(12) NOT NULL,"
  21. +"custname varchar2(50) NOT NULL,"
  22. +"phoneType varchar2(50) NOT NULL,"
  23. +"creditamount varchar2(10) NOT NULL,"
  24. +"payType varchar2(50) NOT NULL)"
  25. +" tablespace ISMP pctfree 60 initrans 1 maxtrans 255 storage (initial 64K) ";
  26. String updateTemp_seq ="CREATE SEQUENCE updateTemp_seq"+tableName+""
  27. +" INCREMENT BY 1" // 每次加1
  28. +" START WITH 1 " // 从1开始计数
  29. +" NOMAXvalue " // 不设置最大值
  30. +" NOCYCLE " // 一直累加,不循环
  31. +" CACHE 10 "; // 缓存10个
  32. // 定义-新增数据临时表
  33. String insertListTemp ="CREATE TABLE insertListTemp"+tableName+"("
  34. +"id integer NOT NULL,"
  35. +"msisdn varchar2(12) NOT NULL,"
  36. +"custname varchar2(50) NOT NULL,"
  37. +"phoneType varchar2(50) NOT NULL,"
  38. +"creditamount varchar2(10) NOT NULL,"
  39. +"payType varchar2(50) NOT NULL)"
  40. +" tablespace ISMP pctfree 60 initrans 1 maxtrans 255 storage (initial 64K) ";
  41. String insertTemp_seq ="CREATE SEQUENCE insertTemp_seq"+tableName+""
  42. +" INCREMENT BY 1" // 每次加1
  43. +" START WITH 1 " // 从1开始计数
  44. +" NOMAXvalue " // 不设置最大值
  45. +" NOCYCLE " // 一直累加,不循环
  46. +" CACHE 10 ";
  47. try {
  48. if(excelPath == null){
  49. OprResult.SetOprResult(request, "导入用户异常","导入用户失败,请选择要导入的内容 !", backUrl,OprResult.FAILURE);
  50. return "/op/oprResult";
  51. }
  52. // 解析得到的用户表集合
  53. List<List<Object>> usrlist = ImportExcelUtil.getExcelList(excelPath.getInputStream(),excelTop);
  54. if(usrlist == null){
  55. OprResult.SetOprResult(request, "导入用户异常", "导入用户信息,数据表格不能有空值 !", backUrl,OprResult.FAILURE);
  56. return "/op/oprResult";
  57. }
  58. // 验证电话、宽带账号
  59. List<String> failMsisdnList = new ArrayList<String>();
  60. List<String> msiddn = new ArrayList<String>();
  61. for(int y =0; y<usrlist.size(); y++){
  62. if(String.valueOf(usrlist.get(y).get(2).toString()).equals("电话号码")){ // 验证电话号码
  63. if(!ValidateUtils.isMobile(usrlist.get(y).get(0).toString())){
  64. failMsisdnList.add(usrlist.get(y).get(0).toString());
  65. usrlist.remove(usrlist.get(y));
  66. y--;
  67. }
  68. }else{
  69. if(ValidateDhmp.validateUserMsisdn(usrlist.get(y).get(0).toString())){ // 验证宽带账号
  70. failMsisdnList.add(usrlist.get(y).get(0).toString());
  71. usrlist.remove(usrlist.get(y));
  72. y--;
  73. }
  74. }
  75. }
  76. int failsize = failMsisdnList.size();
  77. // 去重
  78. for(int y =0; y<usrlist.size(); y++){
  79. if(y<1){
  80. msiddn.add(usrlist.get(y).get(0).toString());
  81. }else{
  82. if(msiddn.contains(usrlist.get(y).get(0).toString())){
  83. usrlist.remove(usrlist.get(y));
  84. y--;
  85. }else{
  86. msiddn.add(usrlist.get(y).get(0).toString());
  87. }
  88. }
  89. }
  90. // 创建临时表和序列 -正确数据表、问题数据表
  91. BatchInsert.goSql(updateListTemp);
  92. BatchInsert.goSql(updateTemp_seq);
  93. BatchInsert.goSql(insertListTemp);
  94. BatchInsert.goSql(insertTemp_seq);
  95. // 导入sql:
  96. String insertSql ="insert into insertListTemp"+tableName+" values(updateTemp_seq"+tableName+".nextval,?,?,?,?,?)";
  97. BatchInsert.exeBatch(insertSql , usrlist); // 批量导入到新增数据表
  98. // 插入问题数据(用户已存在)-sql
  99. insertSql ="insert into updateListTemp"+tableName+" select updateTemp_seq"+tableName+".nextval,"
  100. +"temp.msisdn,temp.custname,temp.phoneType,temp.creditamount,temp.payType"
  101. +" from insertListTemp"+tableName+" temp where temp.msisdn in (select msisdn from usr_end_user )";
  102. BatchInsert.goSql(insertSql);
  103. // 删除问题数据(用户已存在)-sql
  104. String deleteErrorSql ="delete from insertListTemp"+tableName+" where msisdn in (select msisdn from usr_end_user )";
  105. BatchInsert.goSql(deleteErrorSql);
  106. // 只修改数据
  107. String[] col = new String[] {"id","msisdn","custname","phoneType","creditamount","payType"};
  108. List<List<Object>> failList = BatchInsert.selectToList("select * from updateListTemp"+tableName,col);
  109. failsize += failList.size();
  110. StringBuffer failbuffer = new StringBuffer();
  111. failbuffer.append("<br><br>一、请注意保留以下信息,此提示只显示一次 !");
  112. failbuffer.append("<br><br>二、失败数据,");
  113. if(failList != null && failList.size() > 0){
  114. failbuffer.append("<br><br> 账号:");
  115. for(List<Object> fail :failList){
  116. failbuffer.append(fail.get(1)+", ");
  117. }
  118. failbuffer.append("<br><br>原因:用户已经存在,请直接编辑。");
  119. }
  120. for(List<Object> fail : failList){
  121. fail.remove(0);
  122. }
  123. usrlist.removeAll(failList); // 求差
  124. if(failMsisdnList != null && failMsisdnList.size() > 0){
  125. failbuffer.append("<br><br> 账号:");
  126. for(String msisdn :failMsisdnList){ // 电话、宽带账号格式不对
  127. failbuffer.append(msisdn+", ");
  128. }
  129. failbuffer.append("<br><br>原因:电话号码或宽带账号格式不对。");
  130. }
  131. String squence ="select USR_CUSTOMER_SEQ.nextval cust_id from (select 1 from all_objects where rownum <= "+usrlist.size()+")";
  132. List<String> squenceList = BatchInsert.selectSql(squence);
  133. // 拼装customList
  134. List<List<Object>> customList = new ArrayList<List<Object>>();
  135. Long maxCode = (long) 0;
  136. String maxCustCode = "";
  137. for(int i=0; i< usrlist.size(); i++){
  138. List<Object> custom = new ArrayList<Object>();
  139. custom.add(squenceList.get(i)); // usr_customer表的序列值
  140. custom.add(usrlist.get(i).get(1)); // custname
  141. customList.add(custom);
  142. if(i<2){
  143. maxCustCode = usermgrService.findMaxCustCode();
  144. if(maxCustCode!= null && !"".equals(maxCustCode)){
  145. maxCode = Long.parseLong(maxCustCode)+1;
  146. custom.add(String.valueOf(maxCode));
  147. }else{
  148. custom.add(String.valueOf("10000000")); // setCustCode
  149. }
  150. }else{
  151. maxCode += 1;
  152. custom.add(String.valueOf(maxCode)); // setCustCode
  153. }
  154. }
  155. // 客户表insert Sql:
  156. String customerSql ="insert into usr_customer(cust_id,cust_name,cust_code)values(?,?,?)";
  157. BatchInsert.exeBatch(customerSql , customList); // 插入客户表
  158. // 用户表insert Sql:
  159. String userSql ="insert into usr_end_user(user_id,cust_id,msisdn,creditamount,phone_type,user_payment_type,"
  160. +"user_stat,user_prvc_code,user_trade_type,is_black,is_active,language,user_level,is_test_user,"
  161. +"consume_limit,limit_tips,dayfee,monthfee,is_realname)"
  162. +" values(usr_end_user_seq.nextVal, ?,?,?,?,? ,?,?,?,?,? ,?,?,?,?,? ,?,?,?) ";
  163. // 拼装userList
  164. List<List<Object>> userList = new ArrayList<List<Object>>();
  165. for(int i=0;i<usrlist.size();i++){
  166. List<Object> user = new ArrayList<Object>();
  167. user.add(squenceList.get(i)); //cust_id
  168. user.add(usrlist.get(i).get(0));//msisdn
  169. user.add(String.valueOf(usrlist.get(i).get(3))); //creditamount
  170. if("电话号码".equals(String.valueOf(usrlist.get(i).get(2)))){
  171. user.add("1"); //phone_type
  172. }else if("宽带号码".equals(String.valueOf(usrlist.get(i).get(2)))){
  173. user.add("3"); //phone_type
  174. }
  175. if("后付费用户".equals(String.valueOf(usrlist.get(i).get(4)))){
  176. user.add("1"); //user_payment_type
  177. }else if("预付费用户".equals(String.valueOf(usrlist.get(i).get(4)))){
  178. user.add("2"); //user_payment_type
  179. }
  180. user.add("1"); //user_stat
  181. user.add("08"); //user_prvc_code
  182. user.add("0"); //user_trade_type-账户行业类型:默认为家庭
  183. user.add(0); //is_black
  184. user.add(0); //is_active
  185. user.add("01"); //LANGUAGE
  186. user.add("01"); //USER_LEVEL
  187. user.add(0); //IS_TEST_USER
  188. user.add("'3|0|0|0|0|0|0|0|0'");//consumeLimit
  189. user.add("'0|0|0'");//LIMIT_TIPS
  190. user.add("0"); //DAYFEE
  191. user.add("0"); //MONTHFEE
  192. user.add("1"); //IS_REALNAME
  193. userList.add(user);
  194. }
  195. BatchInsert.exeBatch(userSql ,userList); // 正式插入用户表
  196. /*try{
  197. //日志
  198. log(session, UsermgrServiceImpl.class,"exeBatch", "批量新增用户");
  199. log(session, UsermgrServiceImpl.class,"exeBatch", "批量新增客户");
  200. }catch (Exception e){
  201. e.printStackTrace();
  202. }*/
  203. // 删除临时表
  204. String dropSql ="drop table updateListTemp"+tableName;
  205. String dropSql2 ="drop sequence updateTemp_seq"+tableName;
  206. String dropSql3 ="drop table insertListTemp"+tableName;
  207. String dropSql4 ="drop sequence insertTemp_seq"+tableName;
  208. BatchInsert.goSql(dropSql);
  209. BatchInsert.goSql(dropSql2);
  210. BatchInsert.goSql(dropSql3);
  211. BatchInsert.goSql(dropSql4);
  212. Long end = System.currentTimeMillis();
  213. System.out.println();
  214. System.out.println("导入用户信息表"+userList.size()+"条数据,总用时==============================:"+ (end-start)/1000+"秒 。");
  215. System.out.println();
  216. if(failsize > 0){
  217. OprResult.SetOprResult(request, "提示信息", "部分用户信息导入失败,如下:"+failbuffer, backUrl, OprResult.FAILURE);
  218. }else{
  219. OprResult.SetOprResult(request, "提示信息", "用户信息导入成功", backUrl, OprResult.SUCCESS);
  220. }
  221. } catch (EncryptedDocumentException e) {
  222. e.printStackTrace();
  223. OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);
  224. } catch (InvalidFormatException e) {
  225. e.printStackTrace();
  226. OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);
  227. } catch (IOException e) {
  228. e.printStackTrace();
  229. OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);
  230. } catch (Exception e) {
  231. e.printStackTrace();
  232. OprResult.SetOprResult(request, "导入用户异常","导入用户信息失败,请刷新页面后重试 !", backUrl,OprResult.FAILURE);
  233. }
  234. return "/op/oprResult";
  235. }

 

 

 

 

 

 

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

 

 

 

 

 

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

 

  1. package com.mc.common.util;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. import java.sql.Statement;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import com.zznode.ismp.mc.common.MspException;
  11. /**
  12. * 批量导入工具类
  13. * @author JiangYu
  14. */
  15. public class BatchInsert {
  16. // private static String url="jdbc:oracle:thin:@127.0.0.1:9521:orcl";
  17. private static String url = MspConfiguration.getInstance().getParaValue("DBUrl");
  18. // oracle数据库用户名
  19. private static String user = MspConfiguration.getInstance().getParaValue("DBUser");
  20. // oracle数据库密码
  21. private static String password = MspConfiguration.getInstance().getParaValue("DBPassword");
  22. public static Connection conn;
  23. public static PreparedStatement ps;
  24. public static ResultSet rs;
  25. public static Statement st ;
  26. public static Connection getConnection(){ //连接数据库的方法
  27. try {
  28. Class.forName("oracle.jdbc.driver.OracleDriver"); //初始化驱动包
  29. conn = DriverManager.getConnection(url, user, password);
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. return conn;
  34. }
  35. public static void main(String[] args) {
  36. getConnection();
  37. if(conn==null){
  38. System.out.println("与oracle数据库连接失败!");
  39. }else{
  40. System.out.println("与oracle数据库连接成功!");
  41. }
  42. }
  43. /**
  44. * 批量运行sql
  45. * @param con
  46. * @param sql
  47. * @param list
  48. */
  49. public static void exeBatch(String sql,List<List<Object>> list) throws Exception{
  50. try {
  51. StringBuffer sqlbuffer = new StringBuffer();
  52. sqlbuffer.append(sql);
  53. Connection con = getConnection();
  54. con.setAutoCommit(false);// 关闭事务自动提交
  55. final int batchSize = 1000; // 每满1000条数据运行一次
  56. int count = 0;
  57. Long startTime = System.currentTimeMillis();
  58. PreparedStatement pst = (PreparedStatement) con.prepareStatement(String.valueOf(sql));
  59. if(list != null && list.size() > 0){
  60. for (int i = 0; i < list.size(); i++) {
  61. for(int x =0;x<list.get(i).size();x++){
  62. pst.setObject(x+1,list.get(i).get(x));
  63. }
  64. pst.addBatch();// 把一个SQL命令加入命令列表
  65. if(++count % batchSize == 0 ){
  66. pst.executeBatch();
  67. count = 0;
  68. }
  69. }
  70. }
  71. pst.executeBatch();
  72. con.commit();
  73. pst.close();
  74. con.close();
  75. Long endTime = System.currentTimeMillis();
  76. System.out.println("单纯inserrt用时:" + (endTime - startTime));
  77. } catch (Exception e) {
  78. e.printStackTrace();
  79. throw new MspException("网络不畅,请刷新页面后重试 !");
  80. }
  81. }
  82. // 解析数据表
  83. public static List<List<Object>> selectToList(String sql,String[] col){
  84. Connection conn = null;//定义为空值
  85. Statement stmt = null;
  86. ResultSet rs = null;
  87. conn = getConnection();
  88. List<Object> list = null;
  89. List<List<Object>> resultList = new ArrayList<List<Object>>();
  90. try {
  91. stmt = conn.createStatement();//创建一个Statement语句对象
  92. rs = stmt.executeQuery(sql);//执行sql语句
  93. while(rs.next()){
  94. list = new ArrayList<Object>();
  95. for(int i=0; i< col.length; i++){
  96. list.add(rs.getObject(col[i]));
  97. }
  98. resultList.add(list);
  99. }
  100. } catch (SQLException e) {
  101. e.printStackTrace();
  102. }finally{
  103. try {
  104. conn.close();
  105. stmt.cancel();
  106. rs.close();
  107. }catch (SQLException e) {
  108. e.printStackTrace();
  109. }
  110. }
  111. return resultList;
  112. }
  113. // 执行增、删、改sql
  114. public static void goSql(String sql){
  115. Connection conn = null;//定义为空值
  116. Statement stmt = null;
  117. conn = getConnection();
  118. try {
  119. stmt = conn.createStatement();
  120. } catch (SQLException e) {
  121. e.printStackTrace();
  122. }
  123. //4、执行语句
  124. try {
  125. stmt.executeUpdate(sql);
  126. } catch (SQLException e) {
  127. e.printStackTrace();
  128. }
  129. //5、关闭操作
  130. try {
  131. stmt.close();
  132. conn.close();
  133. } catch (SQLException e) {
  134. e.printStackTrace();
  135. }
  136. }
  137. // 单纯查询
  138. public static List<String> selectSql(String sql){
  139. Connection conn = null;//定义为空值
  140. Statement stmt = null;
  141. ResultSet rs = null;
  142. conn = getConnection();
  143. List<String> list = new ArrayList<String>();
  144. try {
  145. stmt = conn.createStatement();//创建一个Statement语句对象
  146. rs = stmt.executeQuery(sql);//执行sql语句
  147. while(rs.next()){
  148. list.add(rs.getString("cust_id"));
  149. }
  150. } catch (SQLException e) {
  151. e.printStackTrace();
  152. }finally{
  153. try {
  154. conn.close();
  155. stmt.cancel();
  156. rs.close();
  157. }catch (SQLException e) {
  158. e.printStackTrace();
  159. }
  160. }
  161. return list;
  162. }
  163. }

 

 

 

 

 

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

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

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码秘术家/article/detail/61845
推荐阅读
相关标签
  

闽ICP备14008679号