天天看点

Java多线程分页查询数据库_java使用多线程查询大批量数据

前言

在某些时候,一旦单表数据量过大,查询数据的时候就会变得异常卡顿,虽然在大多数情况下并不需要查询所有的数据,而是通过分页或缓存的形式去减少或者避免这个问题,但是仍然存在需要这样的场景,比如需要导出一大批数据到excel中,导出数据之前,首先得把数据查询出来吧?这个查询的过程,数据量一旦过大,单线程查询数据将会成为瓶颈,下面尝试使用多线程来尝试查询一张数据量较大的表

由于代码逻辑不是很难,直接上代码,关键的地方会有代码注释和说明,总体实现思路:

查询表的数据总量

线程切分,根据本机CPU的核数配置合适数量的线程处理数,根据数据总量为不同的线程分配不同的查询数据量分段,即不同的线程查询不同分段的数据

将各个查询数据的线程提交至线程池,这里使用的线程是带有返回结果的异步线程

1、测试控制器

@GetMapping("/getSysLogMulti")

@ApiOperation(value = "多线程获取日志数据", notes = "多线程获取日志数据", produces = "application/json")

public List getSysLogMulti() {

return operLogService.getSysLogMulti();

}

2、业务实现类

@Autowired

private MultiThreadQueryUtil multiThreadQueryUtil;

@Override

public ListgetSysLogMulti(){

return multiThreadQueryUtil.getMultiCombineResult();

}

3、多线程实现类

import com.sx.workflow.mapper.WorkflowTaskMapper;

import com.sx.workflow.util.ExcelLocalUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

@Service

public class MultiThreadQueryUtil {

@Autowired

private WorkflowTaskMapper workflowTaskMapper;

public ListgetMultiCombineResult() {

//开始时间

long start = System.currentTimeMillis();

//返回结果

Listresult = new ArrayList<>();

//查询数据库总数量

int count = workflowTaskMapper.selectCountAll();

MapsplitMap = ExcelLocalUtils.getSplitMap(count,5);

int bindex = 1;

//Callable用于产生结果

List> tasks = new ArrayList<>();

for (int i = 1; i <= 5; i++) {

//不同的线程用户处理不同分段的数据量,这样就达到了平均分摊查询数据的压力

String[] nums = splitMap.get(String.valueOf(i)).split(":");

int startNum = Integer.valueOf(nums[0]);

int endNum = Integer.valueOf(nums[1]);

Callableqfe = new ThredQuery(startNum, endNum-startNum+1);

tasks.add(qfe);

bindex += bindex;

}

try{

//定义固定长度的线程池 防止线程过多,这个数量一般跟自己电脑的CPU核数进行匹配

ExecutorService executorService = Executors.newFixedThreadPool(5);

//Future用于获取结果

List> futures=executorService.invokeAll(tasks);

//处理线程返回结果

if(futures!=null&&futures.size() > 0){

for (Futurefuture:futures){

result.addAll(future.get());

}

}

//关闭线程池,一定不能忘记

executorService.shutdown();

}catch (Exception e){

e.printStackTrace();

}

long end = System.currentTimeMillis();

System.out.println("线程查询数据用时:"+(end-start)+"ms");

return result;

}

}

4、不同的线程负责查询自己线程负责的数据分段的数据方法

public class ThredQuery implements Callable{

public static SpringContextUtil springContextUtil = new SpringContextUtil();

private int start;

private int end;

//每个线程查询出来的数据集合

private List datas;

public ThredQuery(int start,int end) {

this.start=start;

this.end=end;

//每个线程查询出来的数据集合

WorkflowTaskService workflowTaskService = springContextUtil.getBean("workflowTaskService");

List count = workflowTaskService.getCurrentTasks(start,end);

datas = count;

}

//返回数据给Future

@Override

public List call() throws Exception {

return datas;

}

}

获取具体的bean的工具类,由于线程中无法注册bean,因此需要通过获取bean的方式来进行数据库查询和交互,代码如下:

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

@Component("springContextUtil")

public class SpringContextUtil implements ApplicationContextAware {

private static ApplicationContext applicationContext; // Spring应用上下文环境

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

SpringContextUtil.applicationContext = applicationContext;

}

public static ApplicationContext getApplicationContext() {

return applicationContext;

}

@SuppressWarnings("unchecked")

public static T getBean(String name) throws BeansException {

return (T) applicationContext.getBean(name);

}

@SuppressWarnings("unchecked")

public static T getBean(Class> clz) throws BeansException {

return (T) applicationContext.getBean(clz);

}

}

最后运行一下程序,通过接口来调用一下,通过执行结果可以看到,我这里单表大概5万多条数据,测试了几次,平均下来,不到2秒的时间,总体来说,还是很快的

Java多线程分页查询数据库_java使用多线程查询大批量数据

本篇内容比较简单,主要是方便后续使用时查阅,希望对看到的同学有用,最后感谢观看!