<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java多線程批量拆分List導(dǎo)入數(shù)據(jù)庫

          共 27094字,需瀏覽 55分鐘

           ·

          2021-09-17 13:12


          來源:blog.csdn.net/kisscatforever/
          article/details/79817039

          • 一、前言
          • 二、直接把list懟進(jìn)Mysql
          • 三、分組把list導(dǎo)入Mysql中
          • 四、多線程分批導(dǎo)入Mysql
          • 五、小結(jié)


          一、前言

          前兩天做了一個(gè)導(dǎo)入的功能,導(dǎo)入開始的時(shí)候非常慢,導(dǎo)入2w條數(shù)據(jù)要1分多鐘,后來一點(diǎn)一點(diǎn)的優(yōu)化,從直接把list懟進(jìn)Mysql中,到分配把list導(dǎo)入Mysql中,到多線程把list導(dǎo)入Mysql中。時(shí)間是一點(diǎn)一點(diǎn)的變少了。非常的爽,最后變成了10s以內(nèi)。下面就展示一下過程。


          二、直接把list懟進(jìn)Mysql

          使用mybatis的批量導(dǎo)入操作:

            @Transactional(rollbackFor = Exception.class)
              public int addFreshStudentsNew2(List<FreshStudentAndStudentModellistString schoolNo
          {
                  if (list == null || list.isEmpty()) {
                      return 0;
                  }
                  List<StudentEntity> studentEntityList = new LinkedList<>();
                  List<EnrollStudentEntity> enrollStudentEntityList = new LinkedList<>();
                  List<AllusersEntity> allusersEntityList = new LinkedList<>();

                  for (FreshStudentAndStudentModel freshStudentAndStudentModel : list) {

                      EnrollStudentEntity enrollStudentEntity = new EnrollStudentEntity();
                      StudentEntity studentEntity = new StudentEntity();
                      BeanUtils.copyProperties(freshStudentAndStudentModel, studentEntity);
                      BeanUtils.copyProperties(freshStudentAndStudentModel, enrollStudentEntity);
                      String operator = TenancyContext.UserID.get();
                      String studentId = BaseUuidUtils.base58Uuid();
                      enrollStudentEntity.setId(BaseUuidUtils.base58Uuid());
                      enrollStudentEntity.setStudentId(studentId);
                      enrollStudentEntity.setIdentityCardId(freshStudentAndStudentModel.getIdCard());
                      enrollStudentEntity.setOperator(operator);
                      studentEntity.setId(studentId);
                      studentEntity.setIdentityCardId(freshStudentAndStudentModel.getIdCard());
                      studentEntity.setOperator(operator);
                      studentEntityList.add(studentEntity);
                      enrollStudentEntityList.add(enrollStudentEntity);

                      AllusersEntity allusersEntity = new AllusersEntity();
                      allusersEntity.setId(enrollStudentEntity.getId());
                      allusersEntity.setUserCode(enrollStudentEntity.getNemtCode());
                      allusersEntity.setUserName(enrollStudentEntity.getName());
                      allusersEntity.setSchoolNo(schoolNo);
                      allusersEntity.setTelNum(enrollStudentEntity.getTelNum());
                      allusersEntity.setPassword(enrollStudentEntity.getNemtCode());  //密碼設(shè)置為考生號
                      allusersEntityList.add(allusersEntity);
                  }
                      enResult = enrollStudentDao.insertAll(enrollStudentEntityList);
                      stuResult = studentDao.insertAll(studentEntityList);
                      allResult = allusersFacade.insertUserList(allusersEntityList);

                  if (enResult > 0 && stuResult > 0 && allResult) {
                      return 10;
                  }
                  return -10;
              }

          Mapper.xml

            <insert id="insertAll" parameterType="com.dmsdbj.itoo.basicInfo.entity.EnrollStudentEntity">
                  insert into tb_enroll_student
                  <trim prefix="(" suffix=")" suffixOverrides=",">
                          id,  
                          remark,  
                          nEMT_aspiration,  
                          nEMT_code,  
                          nEMT_score,  
                          student_id,  
                          identity_card_id,  
                          level,  
                          major,  
                          name,  
                          nation,  
                          secondary_college,  
                          operator,  
                          sex,  
                          is_delete,  
                          account_address,  
                          native_place,  
                          original_place,  
                          used_name,  
                          pictrue,  
                          join_party_date,  
                          political_status,  
                          tel_num,  
                          is_registry,  
                          graduate_school,  
                          create_time,  
                          update_time        </trim>        
                  values
                  <foreach collection="list" item="item" index="index" separator=",">
                  (
                          #{item.id,jdbcType=VARCHAR},
                          #{item.remark,jdbcType=VARCHAR},
                          #{item.nemtAspiration,jdbcType=VARCHAR},
                          #{item.nemtCode,jdbcType=VARCHAR},
                          #{item.nemtScore,jdbcType=VARCHAR},
                          #{item.studentId,jdbcType=VARCHAR},
                          #{item.identityCardId,jdbcType=VARCHAR},
                          #{item.level,jdbcType=VARCHAR},
                          #{item.major,jdbcType=VARCHAR},
                          #{item.name,jdbcType=VARCHAR},
                          #{item.nation,jdbcType=VARCHAR},
                          #{item.secondaryCollege,jdbcType=VARCHAR},
                          #{item.operator,jdbcType=VARCHAR},
                          #{item.sex,jdbcType=VARCHAR},
                          0,
                          #{item.accountAddress,jdbcType=VARCHAR},
                          #{item.nativePlace,jdbcType=VARCHAR},
                          #{item.originalPlace,jdbcType=VARCHAR},
                          #{item.usedName,jdbcType=VARCHAR},
                          #{item.pictrue,jdbcType=VARCHAR},
                          #{item.joinPartyDate,jdbcType=VARCHAR},
                          #{item.politicalStatus,jdbcType=VARCHAR},
                          #{item.telNum,jdbcType=VARCHAR},
                          #{item.isRegistry,jdbcType=TINYINT},
                          #{item.graduateSchool,jdbcType=VARCHAR},
                          now(),
                          now()        
                  )   
                  </foreach>                
            </insert> 

          代碼說明:

          底層的mapper是通過逆向工程來生成的,批量插入如下,是拼接成類似:insert into tb_enroll_student()values (),()…….();

          這樣的缺點(diǎn)是,數(shù)據(jù)庫一般有一個(gè)默認(rèn)的設(shè)置,就是每次sql操作的數(shù)據(jù)不能超過4M。這樣插入,數(shù)據(jù)多的時(shí)候,數(shù)據(jù)庫會報(bào)錯(cuò)Packet for query is too large (6071393 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.,雖然我們可以通過

          類似 修改 my.ini 加上 max_allowed_packet =67108864,67108864=64M,默認(rèn)大小4194304 也就是4M

          修改完成之后要重啟mysql服務(wù),如果通過命令行修改就不用重啟mysql服務(wù)。

          完成本次操作,但是我們不能保證項(xiàng)目單次最大的大小是多少,這樣是有弊端的。所以可以考慮進(jìn)行分組導(dǎo)入。


          三、分組把list導(dǎo)入Mysql中

          同樣適用mybatis批量插入,區(qū)別是對每次的導(dǎo)入進(jìn)行分組計(jì)算,然后分多次進(jìn)行導(dǎo)入:

           @Transactional(rollbackFor = Exception.class)
              public int addFreshStudentsNew2(List<FreshStudentAndStudentModellistString schoolNo
          {
                  if (list == null || list.isEmpty()) {
                      return 0;
                  }
                  List<StudentEntity> studentEntityList = new LinkedList<>();
                  List<EnrollStudentEntity> enrollStudentEntityList = new LinkedList<>();
                  List<AllusersEntity> allusersEntityList = new LinkedList<>();

                  for (FreshStudentAndStudentModel freshStudentAndStudentModel : list) {

                      EnrollStudentEntity enrollStudentEntity = new EnrollStudentEntity();
                      StudentEntity studentEntity = new StudentEntity();
                      BeanUtils.copyProperties(freshStudentAndStudentModel, studentEntity);
                      BeanUtils.copyProperties(freshStudentAndStudentModel, enrollStudentEntity);
                      String operator = TenancyContext.UserID.get();
                      String studentId = BaseUuidUtils.base58Uuid();
                      enrollStudentEntity.setId(BaseUuidUtils.base58Uuid());
                      enrollStudentEntity.setStudentId(studentId);
                      enrollStudentEntity.setIdentityCardId(freshStudentAndStudentModel.getIdCard());
                      enrollStudentEntity.setOperator(operator);
                      studentEntity.setId(studentId);
                      studentEntity.setIdentityCardId(freshStudentAndStudentModel.getIdCard());
                      studentEntity.setOperator(operator);
                      studentEntityList.add(studentEntity);
                      enrollStudentEntityList.add(enrollStudentEntity);

                      AllusersEntity allusersEntity = new AllusersEntity();
                      allusersEntity.setId(enrollStudentEntity.getId());
                      allusersEntity.setUserCode(enrollStudentEntity.getNemtCode());
                      allusersEntity.setUserName(enrollStudentEntity.getName());
                      allusersEntity.setSchoolNo(schoolNo);
                      allusersEntity.setTelNum(enrollStudentEntity.getTelNum());
                      allusersEntity.setPassword(enrollStudentEntity.getNemtCode());  //密碼設(shè)置為考生號
                      allusersEntityList.add(allusersEntity);
                  }

                  int c = 100;
                  int b = enrollStudentEntityList.size() / c;
                  int d = enrollStudentEntityList.size() % c;

                  int enResult = 0;
                  int stuResult = 0;
                  boolean allResult = false;

                  for (int e = c; e <= c * b; e = e + c) {
                      enResult = enrollStudentDao.insertAll(enrollStudentEntityList.subList(e - c, e));
                      stuResult = studentDao.insertAll(studentEntityList.subList(e - c, e));
                      allResult = allusersFacade.insertUserList(allusersEntityList.subList(e - c, e));
                  }
                  if (d != 0) {
                      enResult = enrollStudentDao.insertAll(enrollStudentEntityList.subList(c * b, enrollStudentEntityList.size()));
                      stuResult = studentDao.insertAll(studentEntityList.subList(c * b, studentEntityList.size()));
                      allResult = allusersFacade.insertUserList(allusersEntityList.subList(c * b, allusersEntityList.size()));
                  }

                  if (enResult > 0 && stuResult > 0 && allResult) {
                      return 10;
                  }
                  return -10;
              }

          代碼說明:

          這樣操作,可以避免上面的錯(cuò)誤,但是分多次插入,無形中就增加了操作實(shí)踐,很容易超時(shí)。所以這種方法還是不值得提倡的。

          再次改進(jìn),使用多線程分批導(dǎo)入。

          四、多線程分批導(dǎo)入Mysql

          依然使用mybatis的批量導(dǎo)入,不同的是,根據(jù)線程數(shù)目進(jìn)行分組,然后再建立多線程池,進(jìn)行導(dǎo)入。

            @Transactional(rollbackFor = Exception.class)
              public int addFreshStudentsNew(List<FreshStudentAndStudentModellistString schoolNo
          {
                  if (list == null || list.isEmpty()) {
                      return 0;
                  }
                  List<StudentEntity> studentEntityList = new LinkedList<>();
                  List<EnrollStudentEntity> enrollStudentEntityList = new LinkedList<>();
                  List<AllusersEntity> allusersEntityList = new LinkedList<>();

                  list.forEach(freshStudentAndStudentModel -> {
                      EnrollStudentEntity enrollStudentEntity = new EnrollStudentEntity();
                      StudentEntity studentEntity = new StudentEntity();
                      BeanUtils.copyProperties(freshStudentAndStudentModel, studentEntity);
                      BeanUtils.copyProperties(freshStudentAndStudentModel, enrollStudentEntity);
                      String operator = TenancyContext.UserID.get();
                      String studentId = BaseUuidUtils.base58Uuid();
                      enrollStudentEntity.setId(BaseUuidUtils.base58Uuid());
                      enrollStudentEntity.setStudentId(studentId);
                      enrollStudentEntity.setIdentityCardId(freshStudentAndStudentModel.getIdCard());
                      enrollStudentEntity.setOperator(operator);
                      studentEntity.setId(studentId);
                      studentEntity.setIdentityCardId(freshStudentAndStudentModel.getIdCard());
                      studentEntity.setOperator(operator);
                      studentEntityList.add(studentEntity);
                      enrollStudentEntityList.add(enrollStudentEntity);

                      AllusersEntity allusersEntity = new AllusersEntity();
                      allusersEntity.setId(enrollStudentEntity.getId());
                      allusersEntity.setUserCode(enrollStudentEntity.getNemtCode());
                      allusersEntity.setUserName(enrollStudentEntity.getName());
                      allusersEntity.setSchoolNo(schoolNo);
                      allusersEntity.setTelNum(enrollStudentEntity.getTelNum());
                      allusersEntity.setPassword(enrollStudentEntity.getNemtCode());  //密碼設(shè)置為考生號
                      allusersEntityList.add(allusersEntity);
                  });


                  int nThreads = 50;

                  int size = enrollStudentEntityList.size();
                  ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
                  List<Future<Integer>> futures = new ArrayList<Future<Integer>>(nThreads);

                  for (int i = 0; i < nThreads; i++) {
                      final List<EnrollStudentEntity> EnrollStudentEntityImputList = enrollStudentEntityList.subList(size / nThreads * i, size / nThreads * (i + 1));
                      final List<StudentEntity> studentEntityImportList = studentEntityList.subList(size / nThreads * i, size / nThreads * (i + 1));
                      final List<AllusersEntity> allusersEntityImportList = allusersEntityList.subList(size / nThreads * i, size / nThreads * (i + 1));

                     Callable<Integer> task1 = () -> {
                    studentSave.saveStudent(EnrollStudentEntityImputList,studentEntityImportList,allusersEntityImportList);
                         return 1;
                      };
                    futures.add(executorService.submit(task1));
                  }
                  executorService.shutdown();
                  if (!futures.isEmpty() && futures != null) {
                      return 10;
                  }
                  return -10;
              }

          代碼說明:

          上面是通過應(yīng)用ExecutorService 建立了固定的線程數(shù),然后根據(jù)線程數(shù)目進(jìn)行分組,批量依次導(dǎo)入。一方面可以緩解數(shù)據(jù)庫的壓力,另一個(gè)面線程數(shù)目多了,一定程度會提高程序運(yùn)行的時(shí)間。缺點(diǎn)就是要看服務(wù)器的配置,如果配置好的話就可以開多點(diǎn)線程,配置差的話就開小點(diǎn)。

          五、小結(jié)

          通過使用這個(gè)操作真是不斷的提高了,項(xiàng)目使用技巧也是不錯(cuò)。加油~~ 多線程哦~~

          - END -

          程序汪資料鏈接

          程序汪接的7個(gè)私活都在這里,經(jīng)驗(yàn)整理

          Java項(xiàng)目分享  最新整理全集,找項(xiàng)目不累啦 04版

          堪稱神級的Spring Boot手冊,從基礎(chǔ)入門到實(shí)戰(zhàn)進(jìn)階

          臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

          臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

          字節(jié)跳動總結(jié)的設(shè)計(jì)模式 PDF 火了,完整版開放下載!

          歡迎添加程序汪個(gè)人微信 itwang008  進(jìn)粉絲群或圍觀朋友圈

          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码电影中文字幕 | 国产伦子伦一级A片在线 | 天天爽天天干成人av一区二区三区 | 欧美亚州视频 | 亚洲在钱免费观看 |