入库方法修改为多线程,大幅提高入库效率
This commit is contained in:
@@ -5,6 +5,7 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,6 +18,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||||||
@SpringBootApplication()
|
@SpringBootApplication()
|
||||||
@MapperScan("com.yupi.springbootinit.mapper")
|
@MapperScan("com.yupi.springbootinit.mapper")
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@EnableAsync
|
||||||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||||
public class MainApplication {
|
public class MainApplication {
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.yupi.springbootinit.service.HostInfoService;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.amqp.core.Message;
|
import org.springframework.amqp.core.Message;
|
||||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -39,14 +40,15 @@ public class MQReceiver {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
@RabbitListener(queues = "HOST_INFO_QUEUE")
|
@RabbitListener(queues = "HOST_INFO_QUEUE")
|
||||||
|
@Async
|
||||||
public void receive(List<NewHosts> hosts, Channel channel, Message message) throws IOException {
|
public void receive(List<NewHosts> hosts, Channel channel, Message message) throws IOException {
|
||||||
long deliveryTag = message.getMessageProperties().getDeliveryTag();
|
long deliveryTag = message.getMessageProperties().getDeliveryTag();
|
||||||
try {
|
try {
|
||||||
// 等待所有异步任务完成
|
// 等待所有异步任务完成
|
||||||
hostInfoService.processHosts(hosts).join(); // 这里会抛出异常
|
hostInfoService.processHosts(hosts); // 这里会抛出异常
|
||||||
channel.basicAck(deliveryTag, false);
|
channel.basicAck(deliveryTag, false);
|
||||||
log.info("deliveryTag:{}", deliveryTag);
|
// log.info("deliveryTag:{}", deliveryTag);
|
||||||
log.info("{} 消息消费内容大小-------> {}",DateTime.now(),hosts.size());
|
// log.info("{} 消息消费内容大小-------> {}",DateTime.now(),hosts.size());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
channel.basicNack(deliveryTag, false, false);
|
channel.basicNack(deliveryTag, false, false);
|
||||||
log.error("消息消费失败------->消息内容大小{}", hosts.size(), e);
|
log.error("消息消费失败------->消息内容大小{}", hosts.size(), e);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class MQSender {
|
|||||||
//方法:发送消息
|
//方法:发送消息
|
||||||
public void send(List<NewHosts> list){
|
public void send(List<NewHosts> list){
|
||||||
try {
|
try {
|
||||||
log.info("{} 接收到的消息数量----------->{}", DateTime.now(),list.size());
|
// log.info("{} 接收到的消息数量----------->{}", DateTime.now(),list.size());
|
||||||
this.rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
|
this.rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
|
||||||
//指定你队列的名字
|
//指定你队列的名字
|
||||||
rabbitTemplate.convertAndSend("HOST_INFO_QUEUE",list);
|
rabbitTemplate.convertAndSend("HOST_INFO_QUEUE",list);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class HostInfoServiceImpl extends ServiceImpl<NewHostsMapper, NewHosts> i
|
|||||||
saveBatch(newHosts);
|
saveBatch(newHosts);
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
long totalTimeMillis = stopWatch.getTotalTimeMillis();
|
long totalTimeMillis = stopWatch.getTotalTimeMillis();
|
||||||
log.info("存储花费: {}ms", totalTimeMillis);
|
log.info("当前存储数据量大小 {}, 存储花费: {}ms",newHosts.size(),totalTimeMillis);
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 将异常包装到Future,使调用方能处理
|
// 将异常包装到Future,使调用方能处理
|
||||||
@@ -82,21 +82,25 @@ public class HostInfoServiceImpl extends ServiceImpl<NewHostsMapper, NewHosts> i
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
public CompletableFuture<Void> processHosts(List<NewHosts> hosts) {
|
public CompletableFuture<Void> processHosts(List<NewHosts> hosts) {
|
||||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
this.saveHostInfo(hosts);
|
||||||
|
|
||||||
|
// log.info("当前存储数据量大小 {}",hosts.size());
|
||||||
|
// List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||||
// 分片提交(避免单批次过大)
|
// 分片提交(避免单批次过大)
|
||||||
Lists.partition(hosts, 1500).forEach(batch -> {
|
// Lists.partition(hosts, 1500).forEach(batch -> {
|
||||||
log.info("当前存储数据量大小 {}", batch.size());
|
// log.info("当前存储数据量大小 {}", batch.size());
|
||||||
CompletableFuture<Void> future = this.saveHostInfo(batch);
|
// CompletableFuture<Void> future = this.saveHostInfo(batch);
|
||||||
futures.add(future);
|
// futures.add(future);
|
||||||
});
|
// });
|
||||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
// return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||||
.whenComplete((result, ex) -> {
|
// .whenComplete((result, ex) -> {
|
||||||
if (ex != null) {
|
// if (ex != null) {
|
||||||
log.error("部分批次处理失败", ex);
|
// log.error("部分批次处理失败", ex);
|
||||||
} else {
|
// } else {
|
||||||
log.info("所有批次处理完成");
|
// log.info("所有批次处理完成");
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,11 +2,24 @@
|
|||||||
# @author <a href="https://github.com/liyupi">程序员鱼皮</a>
|
# @author <a href="https://github.com/liyupi">程序员鱼皮</a>
|
||||||
# @from <a href="https://yupi.icu">编程导航知识星球</a>
|
# @from <a href="https://yupi.icu">编程导航知识星球</a>
|
||||||
spring:
|
spring:
|
||||||
|
task:
|
||||||
|
# Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
|
||||||
|
execution:
|
||||||
|
thread-name-prefix: save-task # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
|
||||||
|
pool: # 线程池相关
|
||||||
|
core-size: 10 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
|
||||||
|
max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
|
||||||
|
keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
|
||||||
|
queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
|
||||||
|
allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
|
||||||
|
shutdown:
|
||||||
|
await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
|
||||||
|
await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
|
||||||
application:
|
application:
|
||||||
name: springboot-init
|
name: springboot-init
|
||||||
# 默认 dev 环境
|
# 默认 dev 环境
|
||||||
profiles:
|
profiles:
|
||||||
active: prod
|
active: dev
|
||||||
# 支持 swagger3
|
# 支持 swagger3
|
||||||
mvc:
|
mvc:
|
||||||
pathmatch:
|
pathmatch:
|
||||||
@@ -43,15 +56,16 @@ mybatis-plus:
|
|||||||
configuration:
|
configuration:
|
||||||
map-underscore-to-camel-case: false
|
map-underscore-to-camel-case: false
|
||||||
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
|
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
|
||||||
log-sql:
|
|
||||||
default-executor-type: batch
|
default-executor-type: batch
|
||||||
global-config:
|
global-config:
|
||||||
|
banner: false
|
||||||
db-config:
|
db-config:
|
||||||
logic-delete-field: isDelete # 全局逻辑删除的实体字段名
|
logic-delete-field: isDelete # 全局逻辑删除的实体字段名
|
||||||
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
||||||
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 接口文档配置
|
# 接口文档配置
|
||||||
knife4j:
|
knife4j:
|
||||||
enable: true
|
enable: true
|
||||||
@@ -80,3 +94,12 @@ sa-token:
|
|||||||
token-style: random-128
|
token-style: random-128
|
||||||
# 是否输出操作日志
|
# 是否输出操作日志
|
||||||
is-log: true
|
is-log: true
|
||||||
|
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org.mybatis: off
|
||||||
|
com.baomidou.mybatisplus: off
|
||||||
|
java.sql: off
|
||||||
|
org.apache.ibatis: off
|
||||||
|
com.yupi.springbootinit.mapper.NewHostsMapper: off # 替换成你的 Mapper 包名
|
||||||
|
|||||||
Reference in New Issue
Block a user