心链6----开发主页以及后端数据插入(多线程并发)定时任务

心链 — 伙伴匹配系统

开发主页

信息搜索页修改

image.png
image.png

主页开发(直接list用户)

在后端controller层编写接口去实现显示推荐页面的功能

    /*** 推荐页面* @param request* @return*/@GetMapping("/recommend")public BaseResponse<List<User>> recommendUsers(HttpServletRequest request){QueryWrapper<User> queryWrapper = new QueryWrapper<>();List<User> userList = userService.list(queryWrapper);List<User> list = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());return ResultUtils.success(list);}

前端就先复制搜索结果的代码,在修改一个一些不需要的即可

<!--
User:Shier
CreateTime:14:47
-->
<template><van-cardv-for="user in userList":desc="user.profile":title="`${user.username} (${user.planetCode})`":thumb="user.avatarUrl"><template #tags><van-tag plain type="danger" v-for="tag in tags" style="margin-right: 8px; margin-top: 8px">{{ tag }}</van-tag></template><template #footer><van-button size="mini">联系我</van-button></template></van-card><van-empty v-if="!userList || userList.length < 1" image="search" description="数据为空"/>
</template><script setup>import {onMounted, ref} from "vue";import {useRoute} from "vue-router";import {showFailToast, showSuccessToast} from "vant/lib/vant.es";import myAxios from "../plugins/myAxios.ts";import qs from 'qs'const route = useRoute();const {tags} = route.query;const userList = ref([]); //用户列表onMounted(async () => {// 为给定 ID 的 user 创建请求const userListData = await myAxios.get('/user/recommend', {withCredentials: false,params: {},}).then(function (response) {console.log('/user/recommend succeed', response);showSuccessToast('请求成功');return response?.data;}).catch(function (error) {console.log('/user/recommend error', error);showFailToast('请求失败')});if (userListData) {userListData.forEach(user => {if (user.tags) {user.tags = JSON.parse(user.tags);}})userList.value = userListData;}})</script><style scoped></style>

image.png
修改一下页面边距
image.png

提取用户信息信息卡片

新建文件夹components和文件UserCardList.vue,将主页用户信息卡片提取出来。主页和用户信息搜索页进行引用。

<template><van-cardv-for="user in userList":desc="user.profile":title="`${user.username} (${user.planetCode})`":thumb="user.avatarUrl"><template #tags><van-tag plain type="danger" v-for="tag in user.tags" style="margin-right: 8px; margin-top: 8px" >{{ tag }}</van-tag></template><template #footer><van-button size="mini">联系我</van-button></template></van-card>
</template><script setup lang="ts">
import {UserType} from "../models/user";interface UserCardListProps{userList: UserType[];
}
// 给父组件设置默认值,保证数据不为空
const props= withDefaults(defineProps<UserCardListProps>(),{//@ts-ignoreuserList: [] as UserType[]
});</script>
<style scoped>/* 标签颜色*/.van-tag--danger.van-tag--plain {color: #002fff;}
</style>

然后在Index、SearchResultPage引入UserCardList
image.png

导入数据

模拟 1000 万个用户,再去查询

  1. 用可视化界面:适合一次性导入、数据量可控
  2. 写程序:for 循环,建议分批,不要一把梭哈(可以用接口来控制)要保证可

控、幂等,注意线上环境和测试环境是有区别的导入 1000 万条,for i 1000w

  1. 执行 SQL 语句:适用于小数据量

导入导出

(鱼皮这里应该是屏幕没有放大没有看见字段对应的列信息,idea是可以实现的。)
**导出 **
这里自己选择导出的文件类型和导出的地方路径。(尽量用CSV,exsl格式的话因为编码因为会乱码。)


导入
选择要导入的文件




(导入有风险,自己要想清楚用何种方式导入数据。鱼皮在视频里也重点说过的。)

定时任务

:::info
开启定时任务;注解。

新建InsertUser.java(鱼皮是在once文件夹,我这个是之前命名是起的,都可以无所谓的,自己记得就好。)

插件(idea里搜的)

编写定时任务代码并进行测试(这里的定时取巧,尽量别用,注释掉。)

:::

package com.yupi.usercenter.easyExcel;
import java.util.Date;import com.yupi.usercenter.mapper.UserMapper;
import com.yupi.usercenter.model.domain.User;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;import javax.annotation.Resource;@Component
public class InsertUsers {@Resourceprivate UserMapper userMapper;/*** 循环插入用户*/
//    @Scheduled(initialDelay = 5000,fixedRate = Long.MAX_VALUE )public void doInsertUser() {StopWatch stopWatch = new StopWatch();stopWatch.start();final int INSERT_NUM = 1000;for (int i = 0; i < INSERT_NUM; i++) {User user = new User();user.setUsername("假用户");user.setUserAccount("sifsf");user.setAvatarUrl("https://raw.githubusercontent.com/RockIvy/images/master/img/avatar54.jpg");user.setProfile("阿尼亚");user.setGender(0);user.setUserPassword("12345678");user.setPhone("123456789108");user.setEmail("123861283@qq.com");user.setUserStatus(0);user.setUserRole(0);user.setPlanetCode("931");user.setTags("[]");userMapper.insert(user);}stopWatch.stop();System.out.println( stopWatch.getLastTaskTimeMillis());}
}

数据插入/并发插入

我们需要插入数据: 1.用可视化界面:适合一次性导入、数据量可控 由于编码,主键以及某些字段的问题
(id,createtime等),演示插入失败,这里不推荐 2.写程序:for 循环,建议分批,不要一把梭哈,这里
演示了两种插入数据的方法 首先创建测试方法文件InsertUsersTest,编写批量查询解决

并发执行,这里的线程可自定义或者用idea默认的,两种方法的区别是,自定义可以跑满线程,而默认的
只能跑CPU核数-1,代码区别:就是在异步执行处加上自定义的线程名

并发插入(这里数据量是100000)
并发要注意执行的先后顺序无所谓,不要用到非并发类的集合

private ExecutorService executorService = new ThreadPoolExecutor(16, 1000, 10000, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10000));

// CPU 密集型:分配的核心线程数 = CPU - 1
// IO 密集型:分配的核心线程数可以大于 CPU 核数

:::info
用户插入单元测试,注意打包时要删掉或忽略,不然打一次包就插入一次
:::

package com.ivy.usercenter.service;import com.ivy.usercenter.mapper.UserMapper;
import com.ivy.usercenter.model.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StopWatch;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;/*** @author ivy* @date 2024/5/30 17:00*/
@SpringBootTest
public class InsertUsersTest {@Resourceprivate UserMapper userMapper;@Resourceprivate UserService userService;//线程设置private ExecutorService executorService = new ThreadPoolExecutor(16, 1000, 10000, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10000));/*** 循环插入用户 10000 条耗时20000ms*/@Testpublic void doInsertUser1() {StopWatch stopWatch = new StopWatch();stopWatch.start();final int INSERT_NUM = 10000;for (int i = 0; i < INSERT_NUM; i++) {User user = new User();user.setUsername("假用户");user.setUserAccount("sifsf");user.setAvatarUrl("https://raw.githubusercontent.com/RockIvy/images/master/img/avatar54.jpg");user.setProfile("阿尼亚");user.setGender(0);user.setUserPassword("12345678");user.setPhone("123456789108");user.setEmail("123861283@qq.com");user.setUserStatus(0);user.setUserRole(0);user.setPlanetCode("931");user.setTags("[]");userMapper.insert(user);}stopWatch.stop();System.out.println(stopWatch.getLastTaskTimeMillis());}/*** 循环插入用户  耗时:20000ms* 批量插入用户   10000  耗时: 1817ms*/@Testpublic void doInsertUser2() {StopWatch stopWatch = new StopWatch();stopWatch.start();final int INSERT_NUM = 10000;List<User> userList = new ArrayList<>();for (int i = 0; i < INSERT_NUM; i++) {User user = new User();user.setUsername("假数据");user.setUserAccount("fakeaccount");user.setAvatarUrl("https://img0.baidu.com/it/u=3514514443,3153875602&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500");user.setGender(0);user.setUserPassword("231313123");user.setPhone("1231312");user.setEmail("12331234@qq.com");user.setUserStatus(0);user.setUserRole(0);user.setPlanetCode("213123");user.setTags("[]");userList.add(user);}userService.saveBatch(userList, 1000);stopWatch.stop();System.out.println(stopWatch.getLastTaskTimeMillis());}/*** 并发批量插入用户   100000  耗时: 4769ms*/@Testpublic void doConcurrencyInsertUser() {StopWatch stopWatch = new StopWatch();stopWatch.start();final int INSERT_NUM = 100000;// 分十组int j = 0;//批量插入数据的大小int batchSize = 5000;List<CompletableFuture<Void>> futureList = new ArrayList<>();// i 要根据数据量和插入批量来计算需要循环的次数。(鱼皮这里直接取了个值,会有问题,我这里随便写的)for (int i = 0; i < INSERT_NUM / batchSize; i++) {List<User> userList = new ArrayList<>();while (true) {j++;User user = new User();user.setUsername("假shier");user.setUserAccount("shier");user.setAvatarUrl("https://c-ssl.dtstatic.com/uploads/blog/202101/11/20210111220519_7da89.thumb.1000_0.jpeg");user.setProfile("fat cat");user.setGender(1);user.setUserPassword("12345678");user.setPhone("123456789108");user.setEmail("22288999@qq.com");user.setUserStatus(0);user.setUserRole(0);user.setPlanetCode("33322");user.setTags("[]");userList.add(user);if (j % batchSize == 0) {break;}}//异步执行 使用CompletableFuture开启异步任务CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println("ThreadName:" + Thread.currentThread().getName());userService.saveBatch(userList, batchSize);}, executorService);futureList.add(future);}CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{})).join();stopWatch.stop();System.out.println(stopWatch.getLastTaskTimeMillis());}}

若使用默认线程池,删去
image.png

分页查询

现在启动前后端,查看主页,发现搜查不出,这是因为数据太多需要分页,修改后端接口方法

    /*** 推荐页面* @param request* @return*/@GetMapping("/recommend")public BaseResponse<Page<User>> recommendUsers(long pageSize,long pageNum, HttpServletRequest request){QueryWrapper<User> queryWrapper = new QueryWrapper<>();Page<User> userList = userService.page(new Page<>(pageNum, pageSize), queryWrapper);return ResultUtils.success(userList);}

同时还要引入mybatis的分页插件配置,直接复制文档到config目录

主要不要忘了把扫包的路径改为自己的

package com.yupi.usercenter.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("com.yupi.usercenter.mapper")
public class MybatisPlusConfig {/*** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));return interceptor;}
}

现在去修改前端主页
image.png
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/20617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go-知识并发控制WaitGroup

Go-知识并发控制WaitGroup 1. 认识 WaitGroup2. 基本原理2.1 信号量2.2 数据结构2.3 Add2.4 Wait2.5 Done 3. 小例子3.1 主协程等待子协程执行完成3.2 子协程等待主协程信号3.3 GetFirst 4. 总结 gitio: https://a18792721831.github.io/ 1. 认识 WaitGroup WaitGroup 是Go 应…

机器学习笔记——双线性回归 MF、 FM

双线性模型 在推荐系统领域常常使用 含义是二元函数固定一个自变量时&#xff0c;函数关于另外一个自变量是线性的。 矩阵分解模型MF 如果我们需要对一个用户推荐电影我们应该怎么推荐&#xff1f; 结合用户以及用户对电影的评分&#xff0c;可以猜测用户的偏好&#xff0c;…

Ubuntu 20.04的安装过程

在Ubuntu 20.04的安装过程中&#xff0c;需要遵循一系列步骤确保系统正确无误地配置和启动。下面将详细介绍Ubuntu 20.04的安装过程&#xff1a; 准备工作 下载Ubuntu镜像&#xff1a;需要访问Ubuntu官网下载所需的Ubuntu 20.04桌面版ISO镜像[1]。制作启动盘&#xff1a;下载完…

公网IP地址如何查询?

公网IP地址是指在互联网中可以被全球范围内的设备访问的IP地址。在网络通信中&#xff0c;公网IP地址扮演着重要的角色&#xff0c;它可以标识设备在互联网中的位置。查询公网IP地址是一种常见的网络管理需求&#xff0c;因为它能够提供网络设备的准确位置信息&#xff0c;方便…

AI 绘画爆火背后:扩散模型原理及实现

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

Java进阶学习笔记34——Arrays类

Arrays&#xff1a; 用来操作数组的工具类。 解释说明&#xff1a; 只要知道代码这么写就可以了。 package cn.ensource.d5_arrays;import java.util.Arrays; import java.util.function.IntToDoubleFunction;public class ArraysTest1 {public static void main(String[] arg…

Spark任务调度

Spark任务调度是Spark作业执行的核心组成部分&#xff0c;它负责将作业拆分成多个任务&#xff0c;并将这些任务分配到集群中的工作节点上执行。以下是关于Spark任务调度的详细解释&#xff0c;结合参考文章中的信息&#xff1a; 1. 调度基本概念 作业&#xff08;JOB&#x…

LTspice仿真中设置电阻随时间变化的方法

背景&#xff1a; 笔者找了很多资料都没有看到如何设置电阻、电容等参数随时间变化。但在实际模拟中&#xff0c;总会遇到需要模拟这些量的变化。故撰写此文&#xff0c;供大家参考。 除了模拟随时间变化外&#xff0c;同样的思路也可以模拟随其他变量变化 效果展示 设置电…

Kubernetes 之 ConfigMap

Kubernetes 之 ConfigMap ConfigMap 定义 ConfigMap 是一种 API 对象&#xff0c;用来将非机密性的数据保存到键值对中。使用时&#xff0c; Pod 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。通过使用 ConfigMap 可以将你的配置数据和应用程序代码分开。 Conf…

Linux的MySQL 数据库备份单循环与多循环shell脚本

本次测试为centos7.6 Linux环境下定时备份MySQL数据库。脚本使用mysqldump命令进行单次数据库备份&#xff0c;并将备份文件存储在指定的目录中。 MySQL 数据库备份单循环 #!/bin/bash DATE$(date %F_%H-%M-%S) HOSTlocalhost USER"your_username" PASS"your_…

(delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型

第三部分 高级语言特性 第14章 泛型 ​ Object Pascal 提供的强类型检查对于提高代码的正确性非常有用&#xff0c;这也是我在本书中经常强调的一个主题。不过&#xff0c;强类型检查也可能带来麻烦&#xff0c;因为你可能想编写一个存储过程或类&#xff0c;对不同的数据类型…

32【Aseprite 作图】石头——拆解

1 石头先画轮廓&#xff0c;还是2 4 1 1 2 2 2&#xff0c;这样画一个圆的轮廓 或者2 1 1 3 5 1 1 1 1 2 4 &#xff0c; 2 最暗一层的黑色&#xff0c;做阴影部分&#xff0c;就是7 4 3 2 做最深的部分 各个地方画一些浅色的&#xff0c;做高光部分&#xff0c;上面的高光偏圆…

015、列表_应用场景

1.消息队列 如图所示,Redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。 2.文章列表 每个用户有属于自己的文章列表,现…

前端WebSocket与WiFi:深度探索与实战应用

前端WebSocket与WiFi&#xff1a;深度探索与实战应用 在数字化时代&#xff0c;前端技术与网络通信的紧密结合为我们的生活带来了前所未有的便利。其中&#xff0c;WebSocket和WiFi作为前端网络通信的重要组成部分&#xff0c;更是引发了广泛关注。本文将从四个方面、五个方面…

收银系统源码-千呼新零售2.0【智慧供应链】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货等连锁店使用。 详细介绍请查看下…

FinalShell 配置SSH密钥登陆

转载请标明出处&#xff1a;http://blog.csdn.net/donkor_/article/details/139355489 文章目录 前言生成密钥服务器配置公钥本地配置私钥存储私钥FinalShell配置 总结 前言 本机FinalShell 配置SSH密钥登陆服务器&#xff0c;这样就不再需要使用密码进行登陆了。由于FinalSh…

【StableDiffusion秋叶包反斜杠问题】Failed to find xxx\sd-webui-aki-v4.8\...\xxx.pth

一、问题发生 1.在我额外安装预处理器时报错 意思是没办法找到有这么一个包&#xff08;但我已经把这个包扔进去了&#xff09; 完整报错&#xff1a; Failed to find S:\app_AI\stableDiffusion-webui-aki\sd-webui-aki-v4.8\extensions\sd-webui-controlnet\annotator\dow…

电机测试方法的介绍与功能实现(T测试方法)

目录 概述 1 理论介绍 2 实现原理 2.1 旋转式编码器原理 2.2 系统实现框图 2.3 测速原理 2.4 计算速度值 3 STM32Cube配置项目 3.1 软件版本信息 3.2 配置项目 4 代码实现 4.1 电机速度控制 4.2 速度计算函数 4.3 功能实现 5 测试 概述 本文主要介绍测试电机速…

LangGraph简介

LangGraph 概述及用法 LangGraph 是 LangChain 的一个扩展&#xff0c;旨在通过将步骤建模为图中的边缘和节点&#xff0c;构建具有大型语言模型&#xff08;LLMs&#xff09;的强大和有状态的多角色应用程序。LangGraph 提供了用于创建常见类型代理的高级接口&#xff0c;以及…

Vue项目运行页面禁止缩放【移动端和PC端都禁止缩放】解决方案

Vue项目运行页面禁止缩放【移动端和PC端都禁止缩放】解决方案&#xff0c;有的人手很J,总喜欢放大缩小&#xff0c;从而会导致页面错乱&#xff0c;以下是解决方案&#xff0c;简单有效 效果图PC&#xff1a;滚轮缩放和其他缩放都会禁止 移动端效果图&#xff1a;各种手机平板…