多线程读取数据库导致连接失败解决方案

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程读取数据库导致连接失败解决方案相关的知识,希望对你有一定的参考价值。

问题背景:

某需求需要处理千万级别的数据,按一定规则导出,生成txt或xml文件,单线程处理太慢,写了一个跑了看差不多要处理6~10个小时。想了想还是就用多线程来从数据库中limit不同的数据来进行处理,耗时控制在5分钟以内.相关逻辑为:

 1 //……其他代码
 2 int count = 10000000;//假设共1千万条数据需要读取
 3 int per = 50000;//每次处理5万条
 4 for (int i = 0 ; i < count/per ; i ++){    //创建1000/5=200个线程来处理数据
 5     //使用线程池来处理多线程
 6     ThreadPool.execute(new ProcessTask(i*per,per));
 7 }

8 //……其他代码 9 class ProcessTask implements Runnable{ 10 int beigin,num; 11 public ProcessTask(int begin,int num){ 12 this.begin = begin; 13 this.num = num; 14 } 15 @Overview 16 public void run (){ 17 //线程内容,读取数据 18 List<Data> userlist = XXXService.getDataByLimit(begin,num); 19 //……对读出来的数据进行处理 20 //……其他代码 21 } 22 }

可见,此处通过循环同时创建了200个线程,而这200个线程都需要读取数据库,测试环境下最大连接数设置的是20,此时数据库就容易报错,无法连接。

除了无法连接数据库以外,还可能会导致以下问题:

  • 短时间内大量占用服务器内存,导致卡顿,甚至OOM
  • 在线上环境此处大量占用必定引起其他项目的性能
  • 此接口恶意盗刷可能导致服务器直接宕机

解决方案:

对读取数据库操作进行sleep

 1 //……其他代码
 2 int count = 10000000;//假设共1千万条数据需要读取
 3 int per = 50000;//每次处理5万条
 4 for (int i = 0 ; i < count/per ; i ++){    //创建1000/5=200个线程来处理数据
 5     //使用线程池来处理多线程
 6     ThreadPool.execute(new ProcessTask(i*per,per,i));
 7 }
 8 //……其他代码
 9 class ProcessTask implements Runnable{
10     int beigin,num;
11     int i ;
12     public ProcessTask(int begin,int num,int i ){
13         this.begin = begin;
14         this.num = num;
15         this.i = i ;
16     }
17     @Overview
18     public void run (){
19     //线程内容,读取数据
20     Thread.sleep(i*500);//可以改成更大的值
21     List<Data> userlist = XXXService.getDataByLimit(begin,num);
22     //……对读出来的数据进行处理
23     //……其他代码
24     }
25 }

这样处理后就可以分时的读取数据库,减少服务器的负担,但是时间会变长(sleep操作),200*0.5=100s,不过也是在可以接受的范围内。

 

感觉好像也没多少技术含量……或者说把getDataByLimit方法设置成synchronizd就行了吧,如果是单独使用的情况下……

<--EOF-->

 

以上是关于多线程读取数据库导致连接失败解决方案的主要内容,如果未能解决你的问题,请参考以下文章

从流中读取失败 - MySqlException

导致资产预编译在heroku部署上失败的代码片段

完成端口线程的 OutOfMemoryException

TCP通信 - 服务器开启多线程与read()导致服务器阻塞问题

Qt 4.7:TCP线程,数据传输导致内存泄漏

RandomAccessFile 解决多线程下载及断点续传