1 多线程生成数据
@PostMapping("genData")
public ResponseResult genData(){
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// int threadPoolSize = Math.min(Runtime.getRuntime().availableProcessors() * 2, 64);
int threadPoolSize = Runtime.getRuntime().availableProcessors();
log.info("线程池大小:{}",threadPoolSize);
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (LiuShiJiaZiEnum year : LiuShiJiaZiEnum.values()) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> processYear(year), executor)
.exceptionally(ex -> {
// 记录异常并返回null以避免中断其他任务
log.error("Error processing year " + year, ex);
ex.printStackTrace();
return null;
});
futures.add(future);
}
// 等待所有任务完成,并忽略已经处理过的异常
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
executor.shutdown();
stopWatch.stop();
log.info("Execution time: " + stopWatch.getTotalTimeMillis() + " ms");
return new ResponseResult(true,"生成成功");
}
private void processYear(LiuShiJiaZiEnum year){
List<LiuShiJiaZiEnum> months = liuShiJiaZiService.getMonths(year);
List<LiuShiJiaZiEnum> days = Arrays.asList(LiuShiJiaZiEnum.values());
List<DiZhiEnum> hzs = Arrays.asList(DiZhiEnum.values());
int BATCH_SIZE = 1000;
List<ZpBaziInfo> batch = new ArrayList<>(BATCH_SIZE);
// 遍历年月日时,生成子平八字信息
for (LiuShiJiaZiEnum month: months){
for (LiuShiJiaZiEnum day: days){
for (DiZhiEnum hz: hzs){
LiuShiJiaZiEnum hour = liuShiJiaZiService.getHour(day.getTiangan(), hz);
ZpBaziInfo record = genZpBaziInfo(year, month, day, hour);
batch.add(record);
if (batch.size() >= BATCH_SIZE) {
zpBaziInfoService.saveBatch(batch);
batch = new ArrayList<>(BATCH_SIZE); // 清空批次以备下一轮
}
}
}
}
if (!batch.isEmpty()) {
zpBaziInfoService.saveBatch(batch);// 保存最后一批
}
}
2 五虎遁
这里采用的jdk17,我将原来jdk1.8的代码重写了。
/**
* 根据年,获取月份
* @param year
* @return
*/
public List<LiuShiJiaZiEnum> getMonths(LiuShiJiaZiEnum year) {
return switch (year.getTiangan()){
// 甲己之年丙作首
case JIA,JI -> calculateMonths(LiuShiJiaZiEnum.BINGYIN);
// 乙庚之岁戊为头
case YI,GENG -> calculateMonths(LiuShiJiaZiEnum.WUYIN);
// 丙辛之岁寻庚起
case BING,XIN -> calculateMonths(LiuShiJiaZiEnum.GENGYIN);
// 丁壬壬位顺行流
case DING,REN -> calculateMonths(LiuShiJiaZiEnum.RENYIN);
// 若问戊癸何方发,甲寅之上好追求
case WU,GUI -> calculateMonths(LiuShiJiaZiEnum.JIAYIN);
default -> throw new IllegalArgumentException("年柱甲子错误");
};
}
/**
* 推算月柱
* @param start
* @return
*/
private List<LiuShiJiaZiEnum> calculateMonths(LiuShiJiaZiEnum start){
return IntStream.range(0,12)
.mapToObj(i->{
int end = start.getValue() + i;
end = end>60?end%60:end;
return LiuShiJiaZiEnum.getLiuShiJiaZiEnum(end);
}).collect(Collectors.toList());
}
/**
* 根据天干地支获取对应的六十甲子值(五鼠遁日)
*
* @param tg 天干枚举
* @param dz 地支枚举
* @return 对应的六十甲子枚举值
*/
public LiuShiJiaZiEnum getHour(TianGanEnum tg, DiZhiEnum dz) {
/**
* 甲己还加甲,乙庚丙作初。
* 丙辛从戊起,丁壬庚子居。
* 戊癸起壬子,周而复始求
*/
Map<TianGanEnum, Integer> startOffsets = Map.of(
TianGanEnum.JIA, 1, TianGanEnum.JI, 1,
TianGanEnum.YI, 13, TianGanEnum.GENG, 13,
TianGanEnum.BING, 25, TianGanEnum.XIN, 25,
TianGanEnum.DING, 37, TianGanEnum.REN, 37,
TianGanEnum.WU, 49, TianGanEnum.GUI, 49
);
Integer offset = startOffsets.get(tg);
if (offset == null) {
throw new IllegalArgumentException("Unexpected Tiangan value: " + tg);
}
// 计算最终索引并返回对应的 LiuShiJiaZiEnum
int index = (offset + dz.getValue()-1) % 60;
return LiuShiJiaZiEnum.values()[index];
}
经过测试518400条数据,103.63MB数据,耗费5~6ms中写入到数据库。
SELECT
table_name AS `Table`,
round(((data_length + index_length) / 1024 / 1024), 2) AS `Size in MB`
FROM information_schema.TABLES
WHERE table_schema = 'ziping'
AND table_name = 'zp_bazi_info';