SpringBoot多线程查询实战-查询库中所有数据多线程实现
创始人
2024-12-18 04:08:59
0

文章目录

    • 案例说明
    • 测试结论
    • Controller层核心代码
    • 测试数据生成
    • 测试报告
    • 源码获取

案例说明

本案例我们希望使用三种方式查询数据库某张表下所有数据:

  • 单线程+分页查询获取所有数据
  • 单线程+直接查询获取所有数据
  • 多线程+分页查询获取所有数据

测试结论

​ ​ ​在比较这三种方式的效率时,我们需要考虑几个关键因素:数据量的大小、查询操作的复杂性、以及并行处理的能力。

​ 首先,我们来看 list() 方法。这个方法直接调用 deviceTestOneService.list() 来获取表中的所有数据。如果数据量非常大,那么这种方法可能会导致内存溢出,因为它会一次性加载所有数据到内存中。此外,由于它是同步执行的,没有利用并行处理的能力,所以在处理大量数据时可能会比较慢。

​ ​ 接下来是 getPageAll() 方法。这个方法采用了分页查询的方式,每次只获取一部分数据,从而避免了内存溢出的问题。然而,它也是同步执行的,没有利用多线程或并行处理的能力。如果每次分页查询的数据量仍然很大,或者需要查询的轮数很多,那么这种方法的效率可能仍然会受到限制。

​​ ​ 最后是 multithreading() 方法。这个方法利用了多线程并行处理的能力,将查询任务分配给多个线程同时执行。这样,可以同时从数据库中获取多个数据块,从而提高了整体的查询效率。当然,多线程也带来了一定的复杂性和开销,比如线程创建、管理和同步等。但是,在数据量较大且服务器资源足够的情况下,多线程方法通常能够显著提高查询效率。

​ ​ 综上所述,从效率角度来看,我们可以将这三种方式按以下顺序排序(从高到低)

  • multithreading():利用多线程并行处理,能够同时执行多个查询任务,提高了整体的查询效率。
  • getPageAll():采用分页查询的方式,避免了内存溢出的问题,但仍然是同步执行的。
  • list():直接加载所有数据到内存中,可能导致内存溢出,且没有利用并行处理的能力,效率较低。
    ​​ ​ 需要注意的是,这个排序是基于一般情况下的假设。在实际应用中,效率还受到其他因素的影响,如数据库的性能、网络延迟、服务器资源等。因此,在选择使用哪种方式时,还需要根据具体的场景和需求进行评估和测试。

Controller层核心代码

package com.interviewbar.system.controller;  import com.interviewbar.common.vo.Result; import com.interviewbar.system.entity.DeviceTestOne; import com.interviewbar.system.service.DeviceTestOneService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*;   /**  * @author FangGL  */ @RestController @RequestMapping("/deviceTestOne") public class DeviceTestOneController {      private final DeviceTestOneService deviceTestOneService;      public DeviceTestOneController(DeviceTestOneService deviceTestOneService) {         this.deviceTestOneService = deviceTestOneService;     }      /**      * 查询表中所有数据      * @return      */     @GetMapping("/list")     public Result list() {         List list = deviceTestOneService.list();         return Result.success(list);     }        /**      * 查询表中所有数据      * @return      */     @GetMapping("/getPageAll")     public Result getPageAll() {         List list = new ArrayList<>();          int limit = 50000;         long count = deviceTestOneService.count();         //循环次数         long cycles = count / limit+1;          for (int i = 0; i < cycles; i++) {             long startIdx = i * limit;             long endIdx = (i + 1) * limit;             if (endIdx > count){                 endIdx = count;             }             List list1 = deviceTestOneService.getPageAll(startIdx, endIdx);             list.addAll(list1);         }         return Result.success(list);     }       @GetMapping("/multithreading")     public Result multithreading() {         List list = new ArrayList<>();          int limit = 50000;         long count = deviceTestOneService.count();         //循环次数         long cycles = count / limit+1;         CountDownLatch latch = new CountDownLatch(7);         ExecutorService executorService = Executors.newFixedThreadPool(7);         for (int i = 0; i < 7; i++) {             final int currentIndex = i;             executorService.submit(() -> {                 long startIdx = currentIndex * limit;                 long endIdx = (currentIndex + 1) * limit;                 if (endIdx > count) {                     endIdx = count;                 }                 List list1 = deviceTestOneService.getPageAll(startIdx, endIdx);                 list.addAll(list1);                 latch.countDown(); // 通知完成             });         }          try {             // 等待所有任务完成             latch.await();             // 没有异常发生,开始关闭线程池             executorService.shutdown();             // 等待线程池关闭完成,或者达到超时时间             if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {                 // 如果超时,强制关闭线程池                 executorService.shutdownNow();             }         } catch (InterruptedException e) {             // 发生中断异常,重新设置中断状态             Thread.currentThread().interrupt();             // 尝试关闭线程池             executorService.shutdownNow();         }         return Result.success(list);     } } 

测试数据生成

建表语句

CREATE TABLE `x_device_test_one` (   `line_id` varchar(255) DEFAULT NULL,   `device_id` varchar(255) DEFAULT NULL,   `date_partition` varchar(255) DEFAULT NULL,   `status` varchar(255) DEFAULT NULL,   `card_swipes_count` bigint(20) DEFAULT NULL,   `station_id` int(11) DEFAULT NULL,   `id` int(255) NOT NULL AUTO_INCREMENT,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=340004 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; 数据生成根据自己需求生成适合数据量即可  第一步:运行下面语句 DELIMITER  // CREATE PROCEDURE InsertTestData()   BEGIN       DECLARE i INT DEFAULT 0;       WHILE i < 300000 DO           INSERT INTO x_device_test_one (line_id, device_id, date_partition, status, card_swipes_count, station_id)           VALUES (               CONCAT('line_', FLOOR(RAND() * 1000000)), -- 假设line_id是一个随机生成的字符串               CONCAT('device_', FLOOR(RAND() * 1000000)), -- 假设device_id是一个随机生成的字符串               DATE_FORMAT(NOW() - INTERVAL FLOOR(RAND() * 3650) DAY, '%Y-%m-%d'), -- 假设date_partition是过去3650天内的随机日期               CONCAT('status_', FLOOR(RAND() * 5) + 1), -- 假设有5种状态,编号从1到5               FLOOR(RAND() * 10000), -- 假设card_swipes_count是一个0到9999之间的随机数               FLOOR(RAND() * 1000) -- 假设station_id是一个0到999之间的随机数           );           SET i = i + 1;       END WHILE;   END // DELIMITER ;      第二步:运行下面语句 -- 调用存储过程以插入数据   CALL InsertTestData();    注意:如果你不再需要它,才执行这一条 -- 删除存储过程 DROP PROCEDURE IF EXISTS InsertTestData; 

测试报告

单线程+分页查询获取所有数据-测试报告
平均耗时4.15秒

在这里插入图片描述

单线程+直接查询获取所有数据-测试报告
平均耗时3.14秒

虽然单线程直接查询库中所有数据要比单线程分页快,但是存在极大风险。
在这里插入图片描述

多线程+分页查询获取所有数据-测试报告
平均耗时1秒

在这里插入图片描述

参考文档:https://www.cnblogs.com/iamamg97/p/15579233.html

源码获取

在笔者的代码仓库中已存放本次测试的代码及数据库,欢迎下载并start🤖
https://gitee.com/fanggaolei/multithreading-project

参考文档:https://www.cnblogs.com/iamamg97/p/15579233.html

相关内容

热门资讯

科普!微信玩金花在哪购买房卡,... 微信游戏中心:拼三张房卡,添加微信【8488009】,进入游戏中心或相关小程序,搜索“微信拼三张房卡...
玩家攻略,牛牛房卡制作链接茄子... 您好!微信茄子娱乐大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(茄子娱乐)大厅介绍:...
终于发现!斗牛链接房卡怎么搞,... 微信游戏中心:斗牛房卡,添加微信【71319951】,进入游戏中心或相关小程序,搜索“微信斗牛房卡”...
微信牛牛链接金花房卡/炸金花房... 牛牛是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:86909166许多玩家在游戏中会购买房卡来享受...
我来教你/牛牛房卡出售新天王/... 今 日消息,新天王/皇豪互众房卡添加微信33549083 苹果今日发布了 iOS 16.1 正式版更...
ia攻略/金花房卡制作链接新二... 新二号房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根据...
科普!微信里玩炸金花房卡购买方... 微信游戏中心:炸金花房卡,添加微信【55051770】,进入游戏中心或相关小程序,搜索“微信炸金花房...
终于发现!炸金花微信链接房卡,... 微信游戏中心:炸金花房卡,添加微信【56001354】,进入游戏中心或相关小程序,搜索“微信炸金花房...
苹果ipad刷安卓系统,探索刷... 你有没有想过,你的苹果iPad也能变身成为安卓小能手?没错,就是那个我们平时用来刷剧、办公、游戏的平...
终于找到“金花房卡在哪获取/随... 随意玩是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:160470940许多玩家在游戏中会购买房卡来...
科普!微信里玩炸金花房卡在哪弄... 微信游戏中心:炸金花房卡,添加微信【33903369】,进入游戏中心或相关小程序,搜索“微信炸金花房...
分享!微信群拼三张房卡怎么买/... 拼三张是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:33699510许多玩家在游戏中会购买房卡来享...
正规平台有哪些,牛牛房卡官网海... 您好!微信海米大厅大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(海米大厅)大厅介绍:...
头条推荐!金花房间怎么创建火星... 今 日消息,火星大厅/新道游房卡添加微信33549083 苹果今日发布了 iOS 16.1 正式版更...
重大通报,金花微信链接市场价格... 南瓜大厅/新道游房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 ...
IA解析/牛牛房卡怎么获得玄灵... IA解析/牛牛房卡怎么获得玄灵大厅/房卡客服玄灵大厅是一款非常受欢迎的游戏,咨询房/卡添加微信:88...
科普!怎么开炸金花房卡链接,拼... 微信游戏中心:拼三张房卡,添加微信【8488009】,进入游戏中心或相关小程序,搜索“微信拼三张房卡...
终于发现!微信牛牛房卡哪里有卖... 微信游戏中心:斗牛房卡,添加微信【66336574】,进入游戏中心或相关小程序,搜索“微信斗牛房卡”...
怎么购买微信炸金花房卡/创建金... 微信炸金花是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:15984933许多玩家在游戏中会购买房卡...
推荐一款!牛牛房卡批发平台蝴蝶... 微信游戏中心:蝴蝶大厅房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或相关小程...