java使用多线程及分页查询数据量很大的数据

调用方法###


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

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;

public class QueryTest {
@Autowired
Object myService;

public  List<Map<String, Object>> getMaxResult(String sex) throws Exception{
    long start = System.currentTimeMillis();
    List<Map<String, Object>> result=new ArrayList<>();//返回结果
    
    int count = 20000005;//mydao.getCount(); 通过count查到数据总量

    int num = 10000;//每次查询的条数
    //需要查询的次数
    int times=count / num;
    if(count!=0) {
        times=times+1;
    }
    //开始查询的行数
    int bindex = 0;

    List<Callable<List<Map<String, Object>>>> tasks = new ArrayList<Callable<List<Map<String, Object>>>>();//添加任务
    for(int i = 0; i <times ; i++){
        Callable<List<Map<String, Object>>> qfe = new ThredQuery(myService,sex,bindex, num);
        tasks.add(qfe);
        bindex=bindex+num;
    }
    //定义固定长度的线程池  防止线程过多
    ExecutorService execservice = Executors.newFixedThreadPool(15);

    List<Future<List<Map<String, Object>>>> futures = execservice.invokeAll(tasks);
        // 处理线程返回结果
    if (futures != null && futures.size() > 0) {
        for(Future<List<Map<String, Object>>> future : futures) {
            result.addAll(future.get());
        }
    }
    execservice.shutdown();  // 关闭线程池

    long end = System.currentTimeMillis();
    System.out.println("用时"+(start-end));
    
    return result;
}

}

线程类###


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

public class ThredQuery  implements Callable<List<Map<String, Object>>> {
    private Object myService;//需要通过够早方法把对应的业务service传进来 实际用的时候把类型变为对应的类型
    private String sex;//查询条件 根据条件来定义该类的属性

    private int bindex;//分页index
    private int num;//数量

    /**
     * 重新构造方法
     * @param myService
     * @param sex
     * @param bindex
     * @param num
     */
    public ThredQuery(Object myService,String sex,int bindex,int num){
        this.myService=myService;
        this.sex=sex;
        this.bindex=bindex;
        this.num=num;
    }

    @Override
    public List<Map<String, Object>> call() throws Exception {
        //通过service查询得到对应结果
        List<Map<String, Object>>  list  =new ArrayList<>(); //myService.queryBySex(sex,bindex,num);

        return list;
    }
}
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
是的,当需要导出的数据量很大时,分页查询或者使用多线程并发导出数据可以提高导出数据的效率和性能。 1. 分页查询导出数据 分页查询是将数据分批次查询,每次查询一定数量的数据,然后将查询出来的数据写入到文件中。这样可以避免一次性查询大量数据导致内存溢出的问题,同时也可以减少数据库的负载。 以下是示例代码: ``` import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.sql.*; public class ExportData { public static void main(String[] args) { // JDBC连接参数 String url = "jdbc:mysql://localhost:3306/database?useSSL=false"; String user = "username"; String password = "password"; // 查询语句 String sql = "SELECT * FROM table LIMIT ?, ?"; // 导出数据文件路径 String filePath = "data.txt"; // 每页查询的数据量 int pageSize = 10000; try { // 创建JDBC连接 Connection conn = DriverManager.getConnection(url, user, password); // 获取总数据量 Statement countStmt = conn.createStatement(); ResultSet countRs = countStmt.executeQuery("SELECT COUNT(*) FROM table"); countRs.next(); int total = countRs.getInt(1); countRs.close(); countStmt.close(); // 分页查询数据 int pageCount = (int) Math.ceil((double) total / pageSize); for (int i = 0; i < pageCount; i++) { // 计算分页查询的起始位置和数据量 int offset = i * pageSize; int limit = pageSize; // 执行查询 PreparedStatement stmt = conn.prepareStatement(sql); stmt.setInt(1, offset); stmt.setInt(2, limit); ResultSet rs = stmt.executeQuery(); // 将数据写入文件 BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true)); // 追加写入文件 while (rs.next()) { // 根据数据类型获取字段值 String col1 = rs.getString("col1"); int col2 = rs.getInt("col2"); // ... // 将数据写入文件 writer.write(col1 + "," + col2 + "\n"); } writer.close(); // 关闭查询结果集和语句 rs.close(); stmt.close(); } // 关闭JDBC连接 conn.close(); } catch (SQLException | IOException e) { e.printStackTrace(); } } } ``` 在这个示例中,我们使用分页查询数据分批次查询,每次查询10000条数据,然后将查询出来的数据写入到文件中。 2. 多线程并发导出数据 多线程并发导出数据使用多个线程同时查询数据和写入文件,以提高导出数据的效率和性能。可以将数据分成多个块,每个线程负责查询和写入一个块的数据。 以下是示例代码: ``` import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class ExportData { public static void main(String[] args) { // JDBC连接参数 String url = "jdbc:mysql://localhost:3306/database?useSSL=false"; String user = "username"; String password = "password"; // 查询语句 String sql = "SELECT * FROM table WHERE id >= ? AND id < ?"; // 导出数据文件路径 String filePath = "data.txt"; // 线程池参数 int threadCount = 4; // 线程数量 int pageSize = 10000; // 每页查询的数据量 try { // 创建JDBC连接 Connection conn = DriverManager.getConnection(url, user, password); // 获取总数据量 Statement countStmt = conn.createStatement(); ResultSet countRs = countStmt.executeQuery("SELECT COUNT(*) FROM table"); countRs.next(); int total = countRs.getInt(1); countRs.close(); countStmt.close(); // 计算每个线程查询的数据块 int blockCount = (int) Math.ceil((double) total / pageSize); int blockSize = (int) Math.ceil((double) blockCount / threadCount); // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(threadCount); // 提交任务 List<Future<?>> futures = new ArrayList<>(); for (int i = 0; i < threadCount; i++) { int start = i * blockSize; int end = Math.min((i + 1) * blockSize, blockCount); long from = start * pageSize; long to = end * pageSize; Future<?> future = executor.submit(() -> { try { // 执行查询 PreparedStatement stmt = conn.prepareStatement(sql); stmt.setLong(1, from); stmt.setLong(2, to); ResultSet rs = stmt.executeQuery(); // 将数据写入文件 BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true)); // 追加写入文件 while (rs.next()) { // 根据数据类型获取字段值 String col1 = rs.getString("col1"); int col2 = rs.getInt("col2"); // ... // 将数据写入文件 writer.write(col1 + "," + col2 + "\n"); } writer.close(); // 关闭查询结果集和语句 rs.close(); stmt.close(); } catch (SQLException | IOException e) { e.printStackTrace(); } }); futures.add(future); } // 等待所有任务完成 for (Future<?> future : futures) { future.get(); } // 关闭线程池和JDBC连接 executor.shutdown(); conn.close(); } catch (SQLException | InterruptedException | ExecutionException | IOException e) { e.printStackTrace(); } } } ``` 在这个示例中,我们使用线程池同时查询数据和写入文件,将数据分成多个块,每个线程负责查询和写入一个块的数据。注意,在实际应用中,可能需要根据服务器性能和网络带宽等情况调整线程数量和分块大小,以达到最佳的导出数据效率和性能。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值