首页
留言
导航
统计
Search
1
追番推荐!免费看动漫的网站 - 支持在线观看和磁力下载
2,517 阅读
2
推荐31个docker应用,每一个都很实用
1,314 阅读
3
PVE自动启动 虚拟机 | 容器 顺序设置及参数说明
935 阅读
4
一条命令,永久激活!Office 2024!
618 阅读
5
优选 Cloudflare 官方 / 中转 IP
490 阅读
默认分类
服务器
宝塔
VPS
Docker
OpenWRT
Nginx
群晖
前端编程
Vue
React
Angular
NodeJS
uni-app
后端编程
Java
Python
SpringBoot
SpringCloud
流程引擎
检索引擎
Linux
CentOS
Ubuntu
Debian
数据库
Redis
MySQL
Oracle
虚拟机
VMware
VirtualBox
PVE
Hyper-V
计算机
网络技术
网站源码
主题模板
登录
Search
标签搜索
Java
小程序
Redis
SpringBoot
docker
Typecho
Cloudflare
docker部署
虚拟机
WordPress
群晖
uni-app
CentOS
Vue
Java类库
Linux命令
防火墙配置
Mysql
脚本
Nginx
微醺
累计撰写
264
篇文章
累计收到
11
条评论
首页
栏目
默认分类
服务器
宝塔
VPS
Docker
OpenWRT
Nginx
群晖
前端编程
Vue
React
Angular
NodeJS
uni-app
后端编程
Java
Python
SpringBoot
SpringCloud
流程引擎
检索引擎
Linux
CentOS
Ubuntu
Debian
数据库
Redis
MySQL
Oracle
虚拟机
VMware
VirtualBox
PVE
Hyper-V
计算机
网络技术
网站源码
主题模板
页面
留言
导航
统计
搜索到
264
篇与
的结果
2023-03-20
彻底解决Ubuntu SSH 无法远程登录及root 登录ACCESS Denied 问题
采用VM虚拟机安装了Ubuntu 16.04 ,采用SSH远程连接发现了两个问题(与Centos不一样)。第一,是SSH无法连接上刚建立的虚拟服务器。原因是Ubuntu没有默认安装SSH服务,需要手动安装下。1、 sudo ps -e|grep ssh #查看是否安装了SSH服务(如果显示为空则没安装)2、sudo apt-get update #先更新下资源列表3、sudo apt-get install openssh-server #安装openssh-server4、sudo ps -e|grep ssh #查看是否安装成功5、sudo service sshd start #重新启动SSH服务第二,root 登录ACCESS Denied 问题第一问题解决后,发现远程SSH连接root 登录缓慢并出现如下问题:解决办法如下:sudo vi /etc/ssh/sshd_config把 PermitRootLogin prohibit-password 注释掉增加一行 PermitRootLogin yes 如下图:重启systemctl restart sshd重新登录 SSH 远程用 root 就解决了 ok!
2023年03月20日
40 阅读
0 评论
0 点赞
2023-03-20
ubuntu 使用root用户登录系统
Ubuntu20.04 安装完成之后,默认是没有 root 账户登录权限的,不过我们可以通过创建的普通用户获取管理员权限,然后修改配置和 root 账户的密码,最后实现登录 root 账户,具体操作步骤如下:1. 以普通用户登录系统,创建 root 用户的密码在终端输入命令:sudo passwd root先输入当前管理用户(如用户 coco )的密码,用于提权。然后再输入为 root 用户所设置的密码,输入两次,这样就完成设置 root 用户密码了(注意 Linux 系统下密码是没有回显的)2. 修改50-ubuntu.conf文件在终端输入命令:sudo vim /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf在文件末尾增加如下两行并保存:greeter-show-manual-login=true #手工输入登陆系统的用户名和密码 allow-guest=false #不允许guest登录(可选)3. 修改gdm-autologin文件在终端输入命令:sudo vim /etc/pam.d/gdm-autologin在第三行前面加#以注释掉auth required pam_succeed_if.so user != root quiet_success,随后保存并退出4. 修改gdm-password文件在终端输入命令:sudo vim /etc/pam.d/gdm-password在第三行前面加#以注释掉auth required pam_succeed_if.so user != root quiet_success,随后保存并退出5. 修改/root/.profile文件在终端输入命令:sudo vim /root/.profile将文件末尾的mesg n 2> /dev/null || true这一行注释掉,并随后添加:tty -s&&mesg n || true6. 注销当前用户,登录 root 用户一般修改完配置后最好重启一下reboot点击未列出?输入 root 然后按回车键登录系统
2023年03月20日
77 阅读
0 评论
0 点赞
2023-03-13
Cdnfly 通过修改 hosts 破解授权保姆级教程
Cdnfly 官方文档:http://doc.cdnfly.cn/1790334Cdnfly 是基于 Openresty ,以 lua 脚本语言开发的防 CC 攻击软件。而 Openresty 是集成了高性能 Web 服务器 Nginx ,以及一系列的 Nginx 模块,这其中最重要的,也是我们主要用到的 Nginx lua 模块。Cdnfly 基于 Nginx lua 开发,继承了 nginx 高并发,高性能的特点,可以以非常小的性能损耗来防范大规模的 CC 攻击主控端目前仅支持 Centos-7 和 Ubuntu 1604 系统。因本次教程用到两台服务器演示,故未测试在同一台服务器配置网站及主控端安装。网站搭建A 服务器在宝塔面板新建网站,绑定域名:auth.cdnfly.cn 和 monitor.cdnfly.cn 。设置网站伪静态。location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php/$1 last; break; } } 上传本文附件内压缩包至网站根目录解压。下载地址:https://115.com/s/sw6rlch3hlg?password=g507Cdnfly-v5.1.11.zip访问码:g507主控端安装B 服务器在宝塔面板 /etc 目录下编辑 host 文件。设置 auth.cdnfly.cn 指向刚才配置网站的服务器 IP 。设置完可通过 ping 命令验证。*.*.*.* auth.cdnfly.cn 通过 Xshell 或其他 SSH 工具执行以下命令安装主控:curl http://auth.cdnfly.cn/master.sh -o master.sh && chmod +x master.sh && ./master.sh --es-dir /home/es 安装完成访问主控端 IP 即可访问后台。修改授权节点数量及到期时间。节点安装命令在后台 系统管理 - 系统升级 。错误提示如提示:Job forlma riadb . service failed because the control process exited with error code.See "systemctl status mariadb . servic and "journalctl -xe" for details. 不如重装下系统吧。变更日志2022-7-14 更新修复节点监控功能
2023年03月13日
29 阅读
0 评论
0 点赞
2023-03-11
Spring Boot + Redis 解决重复提交问题,一定用的到
前言在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求,我们来解释一下幂等的概念:任意多次执行所产生的影响均与一次执行的影响相同。按照这个含义,最终的含义就是 对数据库的影响只能是一次性的,不能重复处理。如何保证其幂等性,通常有以下手段:数据库建立唯一性索引,可以保证最终插入数据库的只有一条数据token机制,每次接口请求前先获取一个token,然后再下次请求的时候在请求的header体中加上这个token,后台进行验证,如果验证通过删除token,下次请求再次判断token悲观锁或者乐观锁,悲观锁可以保证每次for update的时候其他sql无法update数据(在数据库引擎是innodb的时候,select的条件必须是唯一索引,防止锁全表)先查询后判断,首先通过查询数据库是否存在数据,如果存在证明已经请求过了,直接拒绝该请求,如果没有存在,就证明是第一次进来,直接放行。Redis实现自动幂等的原理图:搭建Redis的服务Api1、首先是搭建 Redis 服务器。2、引入 springboot 中到的 redis 的 stater ,或者 Spring 封装的 jedis 也可以,后面主要用到的 api 就是它的 set 方法和 exists 方法,这里我们使用 springboot 的封装好的 redisTemplate/** * redis工具类 */ @Component public class RedisService { @Autowired private RedisTemplate redisTemplate; /** * 写入缓存 * @param key * @param value * @return */ public boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 写入缓存设置时效时间 * @param key * @param value * @return */ public boolean setEx(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 判断缓存中是否有对应的value * @param key * @return */ public boolean exists(final String key) { return redisTemplate.hasKey(key); } /** * 读取缓存 * @param key * @return */ public Object get(final String key) { Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key); return result; } /** * 删除对应的value * @param key */ public boolean remove(final String key) { if (exists(key)) { Boolean delete = redisTemplate.delete(key); return delete; } return false; } }自定义注解AutoIdempotent自定义一个注解,定义此注解的主要目的是把它添加在需要实现幂等的方法上,凡是某个方法注解了它,都会实现自动幂等。后台利用反射如果扫描到这个注解,就会处理这个方法实现自动幂等,使用元注解 ElementType.METHOD 表示它只能放在方法上, etentionPolicy.RUNTIME 表示它在运行时@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface AutoIdempotent { }Token创建和检验1、Token服务接口 我们新建一个接口,创建 token 服务,里面主要是两个方法,一个用来创建 token ,一个用来验证 token 。创建 token 主要产生的是一个字符串,检验 token 的话主要是传达 request 对象,为什么要传 request 对象呢?主要作用就是获取 header 里面的 token ,然后检验,通过抛出的 Exception 来获取具体的报错信息返回给前端public interface TokenService { /** * 创建token * @return */ public String createToken(); /** * 检验token * @param request * @return */ public boolean checkToken(HttpServletRequest request) throws Exception; }2、Token的服务实现类 token 引用了 redis 服务,创建 token 采用随机算法工具类生成随机 uuid 字符串,然后放入到 redis 中(为了防止数据的冗余保留,这里设置过期时间为10000秒,具体可视业务而定),如果放入成功,最后返回这个 token 值。 checkToken 方法就是从 header 中获取 token 到值(如果 header 中拿不到,就从 paramter 中获取),如若不存在,直接抛出异常。这个异常信息可以被拦截器捕捉到,然后返回给前端。@Service public class TokenServiceImpl implements TokenService { @Autowired private RedisService redisService; /** * 创建token * * @return */ @Override public String createToken() { String str = RandomUtil.randomUUID(); StrBuilder token = new StrBuilder(); try { token.append(Constant.Redis.TOKEN_PREFIX).append(str); redisService.setEx(token.toString(), token.toString(),10000L); boolean notEmpty = StrUtil.isNotEmpty(token.toString()); if (notEmpty) { return token.toString(); } }catch (Exception ex){ ex.printStackTrace(); } return null; } /** * 检验token * * @param request * @return */ @Override public boolean checkToken(HttpServletRequest request) throws Exception { String token = request.getHeader(Constant.TOKEN_NAME); if (StrUtil.isBlank(token)) {// header中不存在token token = request.getParameter(Constant.TOKEN_NAME); if (StrUtil.isBlank(token)) {// parameter中也不存在token throw new ServiceException(Constant.ResponseCode.ILLEGAL_ARGUMENT, 100); } } if (!redisService.exists(token)) { throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200); } boolean remove = redisService.remove(token); if (!remove) { throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200); } return true; } }拦截器的配置1、Web配置类 实现WebMvcConfigurerAdapter,主要作用就是添加autoIdempotentInterceptor到配置类中,这样我们到拦截器才能生效,注意使用@Configuration注解,这样在容器启动是时候就可以添加进入context中@Configuration public class WebConfiguration extends WebMvcConfigurerAdapter { @Resource private AutoIdempotentInterceptor autoIdempotentInterceptor; /** * 添加拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(autoIdempotentInterceptor); super.addInterceptors(registry); } }2、拦截处理器 主要的功能是拦截扫描到 AutoIdempotent 到注解到方法,然后调用 tokenService 的 checkToken() 方法校验token是否正确,如果捕捉到异常就将异常信息渲染成json返回给前端/** * 拦截器 */ @Component public class AutoIdempotentInterceptor implements HandlerInterceptor { @Autowired private TokenService tokenService; /** * 预处理 * * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); //被ApiIdempotment标记的扫描 AutoIdempotent methodAnnotation = method.getAnnotation(AutoIdempotent.class); if (methodAnnotation != null) { try { return tokenService.checkToken(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示 }catch (Exception ex){ ResultVo failedResult = ResultVo.getFailedResult(101, ex.getMessage()); writeReturnJson(response, JSONUtil.toJsonStr(failedResult)); throw ex; } } //必须返回true,否则会被拦截一切请求 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } /** * 返回的json值 * @param response * @param json * @throws Exception */ private void writeReturnJson(HttpServletResponse response, String json) throws Exception{ PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=utf-8"); try { writer = response.getWriter(); writer.print(json); } catch (IOException e) { } finally { if (writer != null) writer.close(); } } }测试用例1、模拟业务请求类 首先我们需要通过 /get/token 路径通过 getToken() 方法去获取具体的 token ,然后我们调用 testIdempotence 方法,这个方法上面注解了 @AutoIdempotent ,拦截器会拦截所有的请求,当判断到处理的方法上面有该注解的时候,就会调用 TokenService 中的 checkToken() 方法,如果捕获到异常会将异常抛出调用者,下面我们来模拟请求一下:@RestController public class BusinessController { @Resource private TokenService tokenService; @Resource private TestService testService; @PostMapping("/get/token") public String getToken(){ String token = tokenService.createToken(); if (StrUtil.isNotEmpty(token)) { ResultVo resultVo = new ResultVo(); resultVo.setCode(Constant.code_success); resultVo.setMessage(Constant.SUCCESS); resultVo.setData(token); return JSONUtil.toJsonStr(resultVo); } return StrUtil.EMPTY; } @AutoIdempotent @PostMapping("/test/Idempotence") public String testIdempotence() { String businessResult = testService.testIdempotence(); if (StrUtil.isNotEmpty(businessResult)) { ResultVo successResult = ResultVo.getSuccessResult(businessResult); return JSONUtil.toJsonStr(successResult); } return StrUtil.EMPTY; } }2、使用postman请求 首先访问get/token路径获取到具体到token:利用获取到到token,然后放到具体请求到header中,可以看到第一次请求成功,接着我们请求第二次:第二次请求,返回到是重复性操作,可见重复性验证通过,再多次请求到时候我们只让其第一次成功,第二次就是失败:总结本文介绍了使用 springboot 和 拦截器 、 redis 来优雅的实现接口幂等,对于幂等在实际的开发过程中是十分重要的,因为一个接口可能会被无数的客户端调用,如何保证其不影响后台的业务处理,如何保证其只影响数据一次是非常重要的,它可以防止产生脏数据或者乱数据,也可以减少并发量,实乃十分有益的一件事。而传统的做法是每次判断数据,这种做法不够智能化和自动化,比较麻烦。而今天的这种自动化处理也可以提升程序的伸缩性。
2023年03月11日
36 阅读
0 评论
0 点赞
2023-03-08
计算机网络期末复习提纲(全知识点总结)
计算机网络期末复习提纲全知识点总结第一章 概述1.基本概念- 链路,结点,协议和服务,实体和对等实体,各层PDU- C/S模式,B/S模式,P2P模式- LAN,WAN,MAN,PAN的划分- 网络性能参数:速率,带宽,吞吐量,时延,往返时间,信道利用率2.互联网的组成(边缘部分与核心部分的作用)3.电路交换与分组交换,数据报交换和虚电路交换的特点4.TCP/IP体系结构,数据的封装与解封装第二章 物理层1.信号编码:不归零编码,曼切斯特编码2.影响信号失真程度的因素3.传输介质:双绞线,同轴电缆,光纤(单模和多模),无线介质4.几种复用技术的特点:频分复用,时分复用,统计时分复用,波分复用,码分复用5.宽带接入技术:ADSL,HFC,FTTX第三章 数据链路层1.理解数据链路层的地位与作用,三个基本问题2.使用点对点信道的链路层:信道特点,PPP帧格式,零比特填充法和字节填充法,差错检测(CRC)3.使用广播信道的链路层:信道特点,CSMA/CD协议,MAC帧格式,最小帧长和最大帧长4.网卡的功能和MAC地址,帧的类型(单播帧,广播帧,多播帧)5.比较集线器与交换机,交换机的自学习功能及转发帧的过程6.广播域和碰撞域,VLAN,生成树协议STP第四章 网络层1.网络连接设备:中继器,集线器,交换机,路由器的工作层次2.IP地址:分类IP地址;互联网中的IP地址,特殊IP地址(网络地址,广播地址)3.IP地址与硬件地址的关系,ARP协议(ARP原理,ARP缓存,同一局域网使用ARP,跨网使用ARP)4.IP数据报格式:首部长度和总长度,IP分片与重组(标识,标志,片偏移),生存时间TTL,协议,首部检验和5.划分子网:子网划分,子网掩码,根据IP地址和子网掩码计算该IP地址所在网络的网络地址,广播地址,子网数和子网中的主机数6.CIDR(给定一个CIDR地址快,计算最小IP地址,最大IP地址,掩码和地址总数)和路由聚合(给定几个IP地址,计算聚合后的地址)7.ICMP协议:ICMP协议的作用,ICMP差错报文何时产生,由谁产生.PING命令和Tracert命令的工作原理8.路由器:给定拓扑写出路由器(直连路由,静态路由和动态路由,默认路由),路由器根据路由器转发IP数据报的过程9.RIP:距离,距离向量算法,工作过程,特点10.OSPF:链路状态,OSPF的工作过程,OSPF区域11.外部网关协议BGP:寻找可达性的路由,策略路由12.IPv6:ipv6数据报格式,IPv6相比IPv4的变化,IPv6地址的表示,从IPv4相比IPv6的过渡技术13.IP多播:比较(单播,广播,多播,任播),IP多播数据报的封装,多播IP地址与多播MAC地址,IGMP协议的作用14.VPN:私有IP,VPN路由器封装IP数据报的过程,三种VPN类型的判断,NAT路由器封装IP数据报的过程15.MPLS:与传输路由技术的比较,负载均衡与FEC第五章 运输层1.运输层的作用2.UDP和TCP的特点,及使用它们的应用程序,熟知端口号3.UDP:首部格式,检验和4.TCP的首部格式(端口号,序号,确认号,窗口,首部长度,检验和,6个标志位)5.TCP的可靠传输:超时重传机制,TCP流量控制(序号,确认号,确认标志位,窗口,死锁问题与持续计时器),发送缓存和接受缓存的作用,捎带确认与累积确认6.TCP的拥塞控制:网络拥塞的判断,传输轮次与拥塞窗口大小的关系(慢开始与拥塞避免,门限ssthresh,重传计时器超时与三个重复ACK)7.TCP连接:TCP的套接字,三次握手建立TCP连接,四次握手释放TCP连接第六章 应用层1.域名系统DNS1)IP与域名的关系,DNS的作用,域名的结构2)四类域名服务器(根域名服务器,顶级域名服务器,权限域名服务器和本地域名服务器)3)迭代与递归解析域名的方式,DNS缓存2.文件传输协议FTP:FTP协议的作用,控制连接与21号端口,数据连接与20号端口,匿名FTP的三种使用方式3.WWW服务:HTTP协议的作用,URL,在浏览器的地址栏中输入一个URL后发生的报文交互情况,流水线持久连接,HTTP报文,Cookie的作用,三类web文档,搜索引擎4.电子邮件系统:电子邮件系统的组成,E-mail格式,SMTP,MIME,POP3和IMAP的区别,基于万维网的电子邮件5.动态主机配置协议DHCP:DHCP的作用(IP地址,子网掩码,默认网关IP地址,默认DNS服务器IP地址),DHCP的工作过程,IP租约期,DHCP服务器的位置及DHCP中继6. P2P应用:文件分发第七章 网络安全网络攻击的常见方式,对称密码体制和公钥密码体制,数字签名与保密通信,秘钥分配(KDC,CA)第九章 无线局域网两类WLAN,AdHoc,无线传感器网络,CSMA/CA,802.11帧(四个地址)其他1.归纳比较:地址长度(MAC地址,IPv4地址,IPv6地址,端口号)首部长度(帧首部,IPv4首部,IPv6首部)差错检验(帧校验CRC,IPv4,TCP和UDP的校验检验和)路由技术(RIP,OSPF,BGP,MPLS)数据交换(电路交换,报文交换,分组交换)TCP与UDPIPv4与IPv6P2P与C/S搜索引擎(全文检索与分类目录)CSMA/CD与CSMA/CA网络攻击方式(蠕虫,木马,逻辑炸弹,后门入侵,流氓软件,窃听,拒绝服务攻击)2.主要命令Ipconfig命令(/all,/displaydns,/flushdns,/release,/renew)ping命令(-n,-l,-t等参数)Traceroute命令arp命令(-a,-d,-s参数)3.术语:ISP,IXP,Hub,LAN,MAN,WAN,WLAN,VLAN,P2P,C/S,CSMA/CD,CSMA/CA,LiFi,Wifi,ADSL,HFC,FTTH,URL,VPN,IPSec,NAT,ICMP,IGMP,MSS,BGP,自治系统AS,HTTPS,MPLS,AP,SSID,AdHoc,区块链注:粗体为次重点,粗斜体为重点文章详情请访问:计算机网络期末复习提纲(全知识点总结)
2023年03月08日
21 阅读
0 评论
0 点赞
2023-03-06
面试官:从 MySQL 读取 百万 数据进行处理,应该怎么做?问倒一大片!
背景大数据量操作的场景大致如下:数据迁移数据导出批量处理数据在实际工作中当指定查询数据过大时,我们一般使用分页查询的方式一页一页的将数据放到内存处理。但有些情况不需要分页的方式查询数据或分很大一页查询数据时,如果一下子将数据全部加载出来到内存中,很可能会发生 OOM(内存溢出) ;而且查询会很慢,因为框架耗费大量的时间和内存去把数据库查询的结果封装成我们想要的对象(实体类)。举例:在业务系统需要从 MySQL 数据库里读取 100万 数据行进行处理,应该怎么做? 做法通常如下:常规查询:一次性读取 100万 数据到 JVM 内存中,或者分页读取流式查询:建立长连接,利用服务端游标,每次读取一条加载到 JVM 内存(多次获取,一次一行)游标查询:和流式一样,通过 fetchSize 参数,控制一次读取多少条数据(多次获取,一次多行)常规查询默认情况下,完整的检索结果集会将其存储在内存中。在大多数情况下,这是最有效的操作方式,并且由于 MySQL 网络协议的设计,因此更易于实现。举例:假设单表 100万 数据量,一般会采用分页的方式查询:@Mapper public interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> { @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ") Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper); }注:该示例使用的 MybatisPlus。该方式比较简单,如果在不考虑 LIMIT 深分页优化情况下,估计你的数据库服务器就噶皮了,或者你能等上几十分钟或几小时,甚至几天时间检索数据。流式查询流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。如果没有流式查询,我们想要从数据库取 100万 条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。MyBatis 中使用流式查询避免数据量过大导致 OOM ,但在流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。必须先读取(或关闭)结果集中的所有行,然后才能对连接发出任何其他查询,否则将引发异常。MyBatis 流式查询接口 MyBatis 提供了一个叫 org.apache.ibatis.cursor.Cursor 的接口类用于流式查询,这个接口继承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知:Cursor 是可关闭的;Cursor 是可遍历的。除此之外,Cursor 还提供了三个方法:isOpen():用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据;isConsumed():用于判断查询结果是否全部取完。getCurrentIndex():返回已经获取了多少条数据使用流式查询,则要保持对产生结果集的语句所引用的表的并发访问,因为其查询会独占连接,所以必须尽快处理为什么要用流式查询? 如果有一个很大的查询结果需要遍历处理,又不想一次性将结果集装入客户端内存,就可以考虑使用流式查询;分库分表场景下,单个表的查询结果集虽然不大,但如果某个查询跨了多个库多个表,又要做结果集的合并、排序等动作,依然有可能撑爆内存;详细研究了 sharding-sphere 的代码不难发现,除了 group by 与 order by 字段不一样之外,其他的场景都非常适合使用流式查询,可以最大限度的降低对客户端内存的消耗。游标查询对大量数据进行处理时,为防止内存泄漏情况发生,也可以采用游标方式进行数据查询处理。这种处理方式比常规查询要快很多。当查询百万级的数据的时候,还可以使用游标方式进行数据查询处理,不仅可以节省内存的消耗,而且还不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。一次查询指定 fetchSize 的数据,直到把数据全部处理完。Mybatis 的处理加了两个注解: @Options 和 @ResultType@Mapper public interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> { // 方式一 多次获取,一次多行 @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ") @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000000) Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper); // 方式二 一次获取,一次一行 @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ") @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 100000) @ResultType(BigDataSearchEntity.class) void listData(@Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper, ResultHandler<BigDataSearchEntity> handler); }@OptionsResultSet.FORWORD_ONLY:结果集的游标只能向下滚动ResultSet.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变ResultSet.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变fetchSize:每次获取量@ResultType@ResultType(BigDataSearchEntity.class):转换成返回实体类型注意:返回类型必须为 void ,因为查询的结果在 ResultHandler 里处理数据,所以这个 hander 也是必须的,可以使用 lambda 实现一个依次处理逻辑。注意: 虽然上面的代码中都有 @Options 但实际操作却有不同:方式一是多次查询,一次返回多条;方式二是一次查询,一次返回一条;原因: Oracle 是从服务器一次取出 fetch size 条记录放在客户端,客户端处理完成一个批次后再向服务器取下一个批次,直到所有数据处理完成。MySQL 是在执行 ResultSet.next() 方法时,会通过数据库连接一条一条的返回。flush buffer 的过程是阻塞式的,如果网络中发生了拥塞,send buffer 被填满,会导致 buffer 一直 flush 不出去,那 MySQL 的处理线程会阻塞,从而避免数据把客户端内存撑爆。非流式查询和流式查询区别:非流式查询:内存会随着查询记录的增长而近乎直线增长。流式查询:内存会保持稳定,不会随着记录的增长而增长。其内存大小取决于批处理大小BATCH_SIZE的设置,该尺寸越大,内存会越大。所以BATCH_SIZE应该根据业务情况设置合适的大小。另外要切记每次处理完一批结果要记得释放存储每批数据的临时容器,即上文中的 gxids.clear() ;
2023年03月06日
56 阅读
0 评论
0 点赞
2023-03-06
Async/Await 在前端中的应用
async/await 是 ECMAScript 2017 中新增的语法糖,旨在简化异步编程。它基于 Promise ,并通过引入 async 和 await 关键字来使异步代码看起来更像同步代码。使用 async/await使用 async/await 的前提条件是要有异步操作,比如发起 AJAX 请求或操作 DOM 。下面是一个简单的例子,展示如何使用 async/await 发起 AJAX 请求:async function getData(url) { try { const response = await fetch(url); const data = await response.json(); return data; } catch (error) { console.error(error); } } const data = getData('https://example.com/data'); data.then((result) => console.log(result));在上面的例子中,我们定义了一个名为 getData 的异步函数,并将其声明为 async 。该函数接受一个 URL 参数,使用 fetch 函数向服务器发送请求,然后等待响应。一旦响应返回,代码就会继续执行,解析 JSON 数据并将其返回。注意,在 try 代码块中使用了 await 关键字,这告诉 JavaScript 引擎等待该行代码的结果,然后继续执行接下来的代码。如果出现错误, catch 代码块会捕获并处理它们。在上述代码中,我们调用了 getData 函数,并使用 .then() 方法处理返回值。由于 getData 函数返回一个 Promise ,因此可以使用 .then() 处理它的结果。错误处理与 Promise 一样,Async/Await 也需要正确地处理错误。如果一个异步操作失败,它将返回一个拒绝( rejected )状态的 Promise 。为了处理异步操作的错误,我们通常会在 try/catch 块中使用 await 。下面是一个错误处理的例子:async function getData(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); return data; } catch (error) { console.error(error); } }在上述代码中,我们使用 if 语句检查是否从服务器收到了正常响应。如果没有,我们抛出一个错误。这会触发 catch 代码块,允许我们处理错误。并行处理异步任务在很多情况下,我们需要同时处理多个异步任务。这时,可以使用 Promise.all() 方法来并行执行异步任务,并等待它们全部完成后再继续执行代码。下面是一个例子,展示如何同时发起多个 AJAX 请求并等待它们全部完成:async function fetchData() { const urls = ['https://example.com/data1', 'https://example.com/data2', 'https://example.com/data3']; const promises = urls.map(url => fetch(url)); const responses = await Promise.all(promises); const data = await Promise.all(responses.map(response => response.json())); return data; } const data = fetchData(); data.then((result) => console.log(result));在上述代码中,我们首先定义了一个包含多个 URL 的数组。然后,我们使用 map() 方法将每个 URL 转换为一个 fetch() 方法调用,并将这些调用存储在一个新的数组中。接着,我们使用 Promise.all() 方法等待所有 fetch() 调用都返回结果。然后,我们使用 map() 方法将每个响应解析为 JSON 数据,并将这些数据存储在一个新的数组中。最后,我们将包含所有数据的数组返回到调用方。使用 async/await 处理动画效果在 Web 开发中,通常需要在 DOM 元素上应用动画效果。使用传统的 JavaScript 回调函数和 setTimeout() 方法来实现这些效果可能会导致出现回调地狱的问题。通过使用 async/await,我们可以更轻松地在 DOM 上应用动画效果。例如,下面是一个简单的例子,展示如何使用 async/await 实现淡入动画效果:async function fadeIn(element, duration) { element.style.opacity = 0; element.style.display = 'block'; const start = performance.now(); while (performance.now() - start < duration) { const percentage = (performance.now() - start) / duration; element.style.opacity = Math.min(percentage, 1); await new Promise(resolve => requestAnimationFrame(resolve)); } element.style.opacity = 1; }在上述代码中,我们定义了一个名为 fadeIn 的异步函数,并将其声明为 async。该函数接受两个参数:一个 DOM 元素和一个表示动画持续时间的数字(以毫秒为单位)。在函数的主体中,我们首先设置元素的初始状态:将其不透明度设置为 0,并将其显示出来(通过将其 display 样式设置为 "block" )。接着,我们使用 performance.now() 函数获取当前时间,并在每个帧之间进行循环。在循环内部,我们计算从动画开始到当前帧的时间百分比,并使用该百分比来计算元素应该具有的不透明度值。然后,我们使用 requestAnimationFrame() 函数等待下一帧,并将其封装在一个 Promise 中,以便在下一帧完成时恢复函数的执行。最后,我们将元素的不透明度设置为 1 ,以确保最终状态正确。结论Async/await 是现代 JavaScript 中非常有用的功能,它使异步编程变得更加容易和直观。除了处理 AJAX 请求外,在动画效果和其他异步操作方面也非常有用。希望本文对您有所帮助!
2023年03月06日
59 阅读
0 评论
0 点赞
2023-03-04
Typecho 批量更换文章中的图片地址
前言最近,博客将图片都上传到了七牛云对象存储了(关于本站图床的一些配置),本地服务器的图片也删除了。那么,如何批量修改文章中那么多的图片地址呢?批量修改图片地址这里用phpMyAdmin工具进行演示,当然也可以用navicat等数据库管理工具,都是一样的。首先我们需要确定要更换的地址,要注意路径,比如原本本地服务器存储的域名地址是https://www.xxxx.cn/image/2023/。然后你将2023路径下的所有图片,都上传到了对象存储,地址是:https://img.xxxx.cn/image/2023/ 那么这个时候你只需要批量将原本的https://www.xxx.cn/image/ 更改成https://img.xxxx.cn/image (为什么要带上image呢主要防止有些地方链接非图片,被误更改了)。然后打开数据库管理工具,选择 typecho 的数据库,打开 typecho_contents 表,点击SQL,执行下列sql语句。(这里是 更改文章内图片 的)UPDATE typecho_contents SET text = REPLACE(text,'旧域名地址','新域名地址');然后再去 typecho_fields 表执行下列sql语句(这里是 更改封面图片 的)UPDATE typecho_fields SET str_value = REPLACE(str_value,'旧域名地址','新域名地址');执行后,显示批量更改成功,然后就可以返回博客的文章中查看图片链接是否正确,是否能被访问啦!
2023年03月04日
107 阅读
0 评论
2 点赞
2023-03-04
Jenkins+Docker 实现一键自动化部署项目!步骤齐全,少走坑路
本文章实现最简单全面的 Jenkins+docker+springboot 一键自动部署项目,步骤齐全,少走坑路。环境:Centos7+Git(Gitee)简述实现步骤:在 docker 安装 jenkins,配置 jenkins 基本信息,利用 Dockerfile 和 shell 脚本实现项目自动拉取打包并运行。安装 dockerdocker 安装社区版本 CE确保 yum 包更新到最新。yum update卸载旧版本(如果安装过旧版本的话)yum remove docker docker-common docker-selinux docker-engine安装需要的软件包yum install -y yum-utils device-mapper-persistent-data lvm2设置 yum 源yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo安装 dockeryum install docker-ce #由于repo中默认只开启stable仓库,故这里安装的是最新稳定版17.12.0 yum install <自己的版本> # 例如:sudo yum install docker-ce-17.12.0.ce启动和开机启动systemctl start docker systemctl enable docker验证安装是否成功docker version安装 JenkinsJenkins 中文官网安装 Jenkinsdocker 安装一切都是那么简单,注意检查 8080 是否已经占用!如果占用修改端口docker run --name jenkins -u root --rm -d -p 8080:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock jenkinsci/blueocean如果没改端口号的话安装完成后访问地址=> http://{部署Jenkins所在服务IP}:8080此处会有几分钟的等待时间。初始化 Jenkins详情见官网教程=> https://www.jenkins.io解锁 Jenkins进入 Jenkins 容器:docker exec -it {Jenkins容器名} bash # 例如 `docker exec -it jenkins bash`查看密码:cat /var/lib/jenkins/secrets/initialAdminPassword复制密码到输入框里面安装插件选择第一个:安装推荐的插件创建管理员用户此账户一定要记住哦系统配置安装需要插件进入【首页】–【系统管理】–【插件管理】–【可选插件】搜索以下需要安装的插件,点击安装即可。安装 Maven Integration安装 Publish Over SSH(如果不需要远程推送,不用安装)如果使用 Gitee 码云,安装插件 Gitee(Git 自带不用安装)配置 Maven进入【首页】–【系统管理】–【全局配置】,拉到最下面 maven–maven 安装创建任务新建任务点击【新建任务】,输入任务名称,点击构建一个自由风格的软件项目源码管理点击【源码管理】–【Git】,输入仓库地址,添加凭证,选择好凭证即可。构建触发器点击【构建触发器】–【构建】–【增加构建步骤】–【调用顶层Maven目标】–【填写配置】–【保存】此处命令只是 install,看是否能生成 jar 包clean install -Dmaven.test.skip=true保存点击【保存】按钮即可测试该功能测试是否能正常打包构建查看日志点击正在构建的任务,或者点击任务名称,进入详情页面,查看控制台输出,看是否能成功打成 jar 包。该处日志第一次可能下载依赖 jar 包失败,再次点击构建即可成功。查看项目位置cd /var/jenkins_home/workspacell 命令即可查看是否存在运行项目因为我们项目和 jenkins 在同一台服务器,所以我们用 shell 脚本运行项目,原理既是通过 dockerfile 打包镜像,然后 docker 运行即可。Dockerfile在 springboot 项目根目录新建一个名为 Dockerfile 的文件,注意没有后缀名,其内容如下:(大致就是使用 jdk8,把 jar 包添加到 docker 然后运行 prd 配置文件)FROM jdk:8 VOLUME /tmp ADD target/zx-order-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8888 ENTRYPOINT ["Bash","-DBash.security.egd=file:/dev/./urandom","-jar","/app.jar","--spring.profiles.active=prd"]修改 jenkins 任务配置配置如下:-t:指定新镜像名.:表示Dockfile在当前路径cd /var/jenkins_home/workspace/zx-order-api docker stop zx-order || true docker rm zx-order || true docker rmi zx-order || true docker build -t zx-order . docker run -d -p 8888:8888 --name zx-order zx-order:latest备注:我上图用了 docker logs -f 是为了方便看日志,真实不要用,因为会一直等待日志,构建任务会失败加|| true 是如果命令执行失败也会继续实行,为了防止第一次没有该镜像报错保存点击 保存 即可构建查看 jenkins 控制台输出,输出如下,证明成功!验证docker ps 查看是否有自己的容器 docker logs 自己的容器名 查看日志是否正确浏览器访问项目试一试
2023年03月04日
78 阅读
0 评论
0 点赞
2023-03-02
Linux 命令复习
常用命令1、目录操作cd 切换目录cd / 切换到根目录cd ~ 回到个人用户的主目录ls 查看当前目录下所有文件的详细信息 list 的意思ll 查看当前目录下所有文件的详细信息pwd 显示当前目录的全路径. 当前目录.. 上级目录2、文件操作cp 复制mv 重命名、剪切移动位置rm 删除 加上 -rf 就不会出现提示直接删除mkdir test 在当前目录下创建一个 test 文件夹touch a.txt 在当前目录下创建一个文件 a.txt./文件名 执行文件(切换到那个目录然后执行)3、文件编辑vi a.txt 编辑,文件编辑器进入后只能查看,按 i 进入编辑模式,可以移动光标进行文本编辑操作按 esc 退出编辑模式输入:wq 保存并退出(w 代表保存,q 代表退出)输入/abc 回车 搜索文件中包含 abc 的内存4、文件查看cat a.txt 一次性读取并打印 a.txt 文件里的所有信息more a.txt 读取 a.txt 文件,每次读取一屏幕,按空格键翻页tail -200 a.txt 读取后面两百行(看日志排查错误的时候,后面是最新的)tail 是尾巴的意思tail -f a.txt 实时读取这个文件(监控日志用)head -10 a.txt 从前往后读 10 行5、搜索find / -name a.txt 从根目录全局搜索(当问你我想找系统有没有 a.txt 这个文件的时候用)我给你一个日志文件,你给我找出出现错误的那行数据,怎么操作?grep "ClassLoaderLogManager" 日志文件名grep "ERROR" 日志文件名grep "EXCEPTION" 日志文件名有时候只看这行数据没用,因为错误信息太长太多了,我们怎么筛选grep -A 10 "error" test.log -A 表 after 包含这个行以及后面 10 行grep -B 10 "error" test.log -B 表示 before 包含这行和前面 10 行grep -C 10 "error" test.log -C 表示 A 和 B 的结合 包含前 10 和后 10 行其实这样看还是乱,用sz error.log 把日志下载到本地看6、其他命令tar 和 rpm 可以安装 mysql、jdk 等环境ifconfig 查看网络设备信息free -h 检查服务器内存是否足够df -lh 查看磁盘空间大小uname -a 查看系统版本yum install 安装 javajava -jar 可以启动项,但是这个是不是后台启动nohup java -jar 后台启动项目7、进程命令top 查看所有线程 像 window任务管理器ps -ef 看看有没有进程ps -ef|grep 'java' 直接 ps -ef 搜到太多,通过管道符加 grep 只看 java 项目kill -9 进程 id 看查看出进程 id 然后用 kill 删除-9 强行删除ps 和 top 的区别?ps 是查看瞬间的信息,主要查看需要查看的进程top 可以持续监控进程信息,还可以看到性能,还可以操作进程,主要看内存和 cpu 占用情况netstat -anp | grep 8080 查看 8080 端口占用情况8、文件权限文字设定法 1)u:表示属主(user) 2)g:表示同组人(group) 3)o:其他人 (other) 4)a:所有人 (all) 5)+:表示增加权限 -:表示去掉权限 例如:修改 main.c 文件的所有者权限:1).取消写权限:chmod u-w main.c2).成为可写可读的chmod u=rw main.c3).同时修改 main.c 的属主权限和组用户权限:chmod u-w,g+x main.c2)数字设定法 采用数字设定法时,权限通常由三位数字组成,每一位数字代表一种角色的权限。每个角色的数值由其所具有的权限对应的数值之和构成;1)写权限 r : (read)读权限 ,值为 4(100)2)读权限 w : (write)写权限 ,值为 2(010)3)执行权限 x: (execute)执行权限 ,值为 1(001)4)格式: chmod nnn 文件名
2023年03月02日
53 阅读
0 评论
0 点赞
1
...
20
21
22
...
27