Linux
Linux:类Unix,同Git作者Linus,符合GPL(General Public License)可使用、修改、再发布。
Linux四部分:
- 内核:驱动、内存管理、进程管理、文件系统、网络协议栈…。作用:管理硬件和提供最基本的系统服务
- 系统库:libc\ibm\libpthread\libdl\第三方库…。作用:提供常用函数和接口供开发使用。
- shell:
- 应用程序APP:Nginx MySQL Git Vim
发行版:还有包管理器、GUI、系统工具等,比如Ubuntu(个人用户)、Debian、CentOS、Kali(网络安全和渗透测试)
安装Linux:虚拟机工具(VMware、VirtualBox、Hyper-V(WSL)、Multipass)、Docker、云服务器
Linux根目录:home\root\bin\sbin\usr\opt\etc\lib\dev\mnt\boot\sys\proc\var\temp。
tip:bin\lib 都在usr下
Vim
插入模式:aio
进入插入模式。
命令模式:
-
移动:
h j k l
左下上右;ctrl + f/b/d/u
下页、上页、下半页、上半页;^ $
行首、行末。gg G 3g
表示首行、尾行、第三行。:3
表示第三行。 -
3yy
复制三行;3dd
删除三行,D
清空本行;3p
表示复制三次粘贴板上的内容。ctrl + r
表示撤回,u
表示重做。
行末模式:
- 查找:
/hello | ?hello
表示向下、向上查找。n | N
表示下一个、上一个。/hello\c
表示无视大小写 - 替换:
:2,5s/hello/world/g
表示2,5行,g表示此行全部。:s/hello/world
表示此行第一个替代。:%s/hello/world
表示每行第一个替代。- 退出保存
:wq
。:set nu/nonu
set ic
syntax on
。
- 退出保存
~\.vimrc
配置文件,rc表示run commands。
常用命令
# t:time、r:reverse、i:inode
ls -haltri
echo "hello world" > hello.txt # > 覆盖、>> 追加
touch hello.txt # 创建文件、更新文件时间
ln -s hello.txt hello_soft.txt / ln hello.txt hello_hard.txt
# 硬连接:文件; 软连接:文件或目录
# 权限
chmod ugoa+-rwx/777 hello.txt / chmod root:root file
# 创建文件夹、复制、移动
mkdir -p dir1/dir2
cp -r dir1 dir_copy
mv hello.txt dir/hello_move.txt
date whoami pwd tree
du # 目录
df -h # 磁盘
which ls
# 安装jdk8
apt list | grep jdk / sudo apt install openjdk-8-jdk
# tar -c 压缩, -x 提取
tar -c(z)vf file.tar/file.tar.gz file1 file2
# curl: client url用于http(s) (S)FTP SMTP。
# -o new_file.txt ; -s 表示silent不显示进度和错误,只显示真正的内容(正文); -f表示fail时不输出信息
curl -OL https://example.com/file.txt
2
# 其中tty表示Teletypewriter, tty1,tty2表示终端界面; ?表示没有终端相连
ps -ef # e表示所有 f表示信息
# UID PID PPID
# lsof : list open file
# -u user; -p pid; -i :80/tcp/udp; file 表示打开
lsof
# FD文件描述符: cwd/rtd/dir/txt/NOFD/mem/pipe/socket/chr/blk
# TYPE: REG(常规文件)DIR(目录)CHR(字符设备)
# 终止指定服务
ps -ef | grep mysql # 找到mysqld
kill $(pidof mysqld) # 这个命令是/usr/bin/
kill $(pidof redis-server) # 同上
systemctl status/start/stop/restart/reload/enable/disable mysql.service
更新软件
sudo apt update
sudo apt upgrade redis -y # 如果源地址的版本本身就低
# 需要看对应包的官网
# 命令:软件的源地址添加到/etc/apt/sources.list.d/;
# ppa:Launchpad Person Package Archive。redis在ppa会有新版本
sudo add-apt-repository ppa:redislabs/redis
sudo apt update
sudo apt upgrade redis-server -y
redis-server --version
如何在win下传输给linux
scp ./index.js zql@localhost:/home/zql
帮助文档
Log
Shell
脚本的作用:定时处理(比如定时清理、定时备份)、批处理…
Shell种类:sh、bash(默认)、csh、ksh、zsh、powershell。可以cat /etc/shells
查看。
.profile
和 .bashrc
:用户打开bash前会使用这两个文件进行初始化环境。配置之后使用. bashrc 或 source .bashrc
/etc/bash.bashrc
下的文件是对所有用户都有效。
环境变量
echo $SHELL # 默认bash
echo $HOME
echo $PATH
echo $0 # 表示当前的shell解释器。默认bash
export name=adair # 在运行的shell中就可以获取
常用的$:
- $0、$1、 2 、 2、 2、#:表示文件名、第一个参数、第二个参数、参数个数
- ∗ 、 *、 ∗、@:前者表示作为整体;后者表示按参数传递
- ? 、 ?、 ?、 、 、 、!:表示最后一个命令返回的结果;表示此进程PID;最后一个后台命令的PID
if中的数字比较:eq、ne、lt、le、gt、ge。
if中的字符串比较[[ "$str1" == "$str2" ]]
:!=、>、== *、=~、-z、-n
举个例子
#!/bin/bash # 默认解释器
is_prime() {
local num=$1 # 局部变量必须使用local,否则为全局变量
if [ $num -lt 2 ]; then
return 1
fi
for ((i=2; i*i<=num; i++)); do
if [ $((num % i)) -eq 0 ]; then
return 1
fi
done
return 0
}
read -p "输入数字:" number
if ! [[ "$number" =~ ^[0-9]+$ ]]; then # 正则表达式符
echo "no number"
exit 1
fi
if is_prime $number; then # 函数返回0表示OK
echo "$number 是素数"
else
echo "$number 不是素数"
fi
猜数字
#!/bin/bash
# 等效 $(($RANDOM%10+1))
number=$(shuf -i 1-10 -n 1) # 也可以使用反引号
echo "随机数为$number"
while true; do
echo "输入猜的值"
read guess
if [[ $guess -eq $number ]]; then
echo "对了, 请选择是否继续y/n"
read choice
if [[ $choice = "y" ]] || [[ $choice = "Y" ]]; then
number=$(($RANDOM % 10 + 1))
echo "随机数为$number"
continue
else
break
fi
elif [[ $guess -lt $number ]]; then
echo "小了"
else
echo "大了"
fi
done
管道:
如果输入bash confirm.sh
,则会一直循环输入。可以直接yes | bash confirm.sh
#!/bin/bash
for ((i=0; i<3; i++)); do
read -p "输入y|n" flag # 不会
echo "i=$i flag=$flag"
if [ "$flag" == "y" ]; then
continue
fi
done
shell也可以结合:
- grep awk sed 等文本处理
- 函数和数组等高级特性。
- 系统管理和监控
RegEx
基本字符匹配:.、[ ]、[^ ]、|、
字符类:\d、\w、\s、\D、\W、\S。定位符:^、$、\b、\B、
量词:?、+、*、{n}、{n,m}、{n,}。贪婪匹配:ab{3,}、ab{3,}?
旗帜:i、m、s、g、
分组:(abc)、(?:abc)
前瞻:dog(?=cat)、dog(?!cat)。后顾:(?<=cat)dog、(?<!cat)dog
前面的字符都是有特定意义的,如果需要这个字符本身,需要进行转义。但是转义字符同样需要转义\\
。
基本类型:^$. [1-8B-Yc-x] [^] | \d \w \b \s \大写
量词:? + * {n} {n,m} {n,} {n,}?
前瞻:dog(?=cat) dog(?!cat) 后顾:(?<=cat)dog (?<!cat)dog
分组:(abc) (?:abc)。\1
旗帜:i\g\s\m
部分解释:
.
匹配除\n
的任意字符,s
让.
也可匹配\n
^$
表示文本开始和结束。m
让^$
表示每行开始和结束。\b
:比如\b\d+\b
匹配%300
而不是s300
其他版本的RE:
- POSIX基本的BR、扩展的ERE。
- 其他版本的比如Python、Java、JS等。具体情况看文档。
拓展结合:
- grep 和 sed 和 awk
Git
版本控制系统:集中式(比如:SVN)、分布式(比如Git)
Git的使用方式:命令行、GUI、IDE插件/扩展。
git配置:
# system 系统配置/etc/gitconfig:对所有用户生效。global 全局配置~/.gitconfig:所有仓库生效。 不带范围.git/config:默认此仓库
git config --global user.name "adair"
git config --global user.email "123@qq.com"
git config --global credential.helper store # 存储密码,不用git push每次都要输入密码
git config --global --list # 查看属性
.gitignore的内容:
- 中间文件或者结果文件,class文件\o文件
- log\temp
- user\password、Token等
.a # 忽略所有a类型文件
!lib.a # 不包括lib.a
/TODO # 忽略根目录下的TODO文件
build/ # 忽略任何目录的bulid文件夹
doc/*.o # 忽略doc当前目录下o
doc/**/*.class # 忽略doc所有下的class
不过项目都有相应的模板,不用自己写。https://github.com/github/gitignore
.git/ 文件夹
- config:配置的信息,core、user、branch( -a)
- refs/ (分支):heads/ (本地分支);remotes/(远程);tags/
- index:暂存区指针; HEAD: 版本库中。 指向object/:里面都是对象
- logs/ :HEAD(git log的内容);refs/:相应git branch -a其他所引用的内容
创建仓库:
# 本质都是有.git才是仓库。否则就是个普通文件夹
git init # 把当前文件夹为git仓库
git init local-git # 创建文件夹local-git为git仓库
git clone url # 克隆
git clone git@github.com:name/repo.git
git clone git@192.168.8.242:v40_7.1.git
添加和提交
# 工作区、暂存区、本地库。push 远程库
ls # 工作区ls
git ls-files # 暂存区ls
git status # 状态:??(Untracked)、M(modifid)、A(added)、D(deleted)、R(renamed)、U(updated)、
修改file # 返回 git restore file \ git checkout file
git add file # 返回 git restore --staged file \ git reset HEAD(原理) \
git commit -m "message" # -a -v
git commit --amend # 补充提交, 可以-m
git log # --online --graph
版本回退
# 回退之前的版本
git reset --soft commmitID # 指定commitID,且恢复工作区和暂存区
git reset --hard commmitID # 指定commitID的,不恢复
git reset commmitID # 指定commitID,且恢复工作区。默认--mixed
# 从之前的版本到当前版本
git reflog # 查看所有的提交的commitID
# HEAD 当前版本
# HEAD^ HEAD~ 上一个版本
# HEAD~2 上两个版本
内容对比
git diff # 工作区 vs 暂存区
git diff HEAD # 工作区 vs 本地库
git diff commitID1 commitID2 # 两个版本的比较,
git diff commitID1 commitID2 file.txt # 只比较file.txt
# 也可以使用HEAD
git diff 分析
zql@adair-pc:~/git-learn/123$ git diff HEAD
diff --git a/m1 b/m1 # a/m1: 新版 b/m1: 旧版
index 0e6c128..83e9726 100644 # 新版和旧版索引(hash) 100普通文件, 644权限
--- a/m1
+++ b/m1
@@ -1,3 +1,4 @@ # 旧版:1,3行。 新版:1,4行
123456
123
q
+123 # +表示新增的
删除文件
git rm file.txt # 综合 rm file.txt(工作区) 和 git rm --cached file.txt(暂存区)
git mv m1.txt m2.txt # 改名,git status . 出现renamed
分支
git branch # 查看本地分支; -r:remote; -a:all;
git branch dev # 创建分支。git branch -d dev # 删除分支,没有合并则需要D
git checkout/switch dev # 切换分支。checkout -b,创建并切换
# main、dev合并分支,不冲突
git merge dev # 当前在main,则合并dev分支。并且自动会让你输入message,表示一次提交commitID。
# main、feat合并分支,冲突
git merge feat # 此处会把冲突的文件内容合并,重新整理冲突文件。
git commit -am "zql:conflict merge" # 需要重新提交,产生commitID
git merge --abort # 表示终止提交
# rebase
git rebase dev # 表示以dev为根,把main接到dev上。形成直线历史
git rebase main # 同理
git merge dev冲突
# 提示冲突,
<<<<<<< HEAD
456
=======
123
>>>>>>> dev
# 修改冲突之后在进行git commit
通过(github.com gitee.com)账户名和密码的方式克隆remote。
ssh配置,远程克隆到本地:
- 本地生成公钥密钥。
cd ~/.ssh # 切换到~/.ssh下
ssh-keygen -t rsa -b 4096 # rsa类型,4096个bit位数
# 输入相应的名称比如demo,密码demo
# 生成demo.pub,密钥demo
vim config # 增加以下内容
```
Host github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/demo
```
-
把公钥复制到GitHub中。
ssh -T git@gitee.com
测试 -
本地创建一个空仓库,
git remote add origin git@github.com:adair-zhang/learn-github.git
关联远程即可。
tip:这样创建空库再关联太慢了,不如clone。
本地推送到远程:
- GitHub中创建一个空仓库
- 在本地仓库中进行连接GitHub的空仓库
git remote add origin git@github.com:adair-zhang/learn-github.git
git branch -M main # 强制修改当前名(默认为master),修改为main
git push # git push -u origin main 第一次推送到远程。main其实是main(本地):main(远程)缩写
git fetch # 默认git fetch origin main,此时并不在最新的commitID。然后合并git merge
git pull # 等效fetch + merge。默认是git pull origin main
代码托管平台:
- GitHub、gitee、gitlab
- 私有化部署:在自己服务器上部署一个gitlab代码托管平台。可以使用Docker进行部署。
# 比如my-repo是本地关联到github上。
git remote add gitlab git@gitlab.com:name/myrepo.git # 本地再次关联到gitlab上
git remote -v # 可以查看本地关联远程的情况
git push gitlab main # 推送到gitlab
git remote add github2 git@github.com:adair-zhang/first-repo.git # 关联其他仓库
git remote -v # 表示仓库关联的远程信息
git的GUI:GitHub Desktop、SourceTree、GitKraken等
也可以在VS code中进行操作:
- windows安装git
- 然后可以使用vs code中的git
git本质
常用命令
拓展配置:
- post-git
git心得:
commit
之前先review
,查看代码是否错误,规范- 平时开发
test
分支,不要在master
分支
C语言
丹尼斯创造为了Unix编写。
范围:Unix\Linux\Windows、git\vim、MySQL\Redis、Nginx
静态语言:编译时确定变量类型, C\C++\Java\Rust
动态语言:运行时确定变量类型,Python\JavaScript\Ruby\PHP
编译器:
- GCC:GNU Compiler Collection,包含了C、C++、Objective-C、Ada、Go等多种编译器
- Clang:编译C、C++、Objective-C、Objective-C++的编译器前端。采用LLVM为后端,在MacOS下使用
安装开发开发环境:MinGW,安装后 gcc -v
测试。
IDE:CLion、Code::Blocks
VS code
安装好MinGW中的gcc。vs code中不提供编译器。
vs code中然后再增加扩展中,Code Runner
就可以直接运行C的源码了
基本语法
数据类型:
- 基本数据类型:short、int、long、long long、char、float、double
- 派生数据类型:数组、指针、结构体、枚举、共用体、void
#define MAX 100 // 宏定义
int num; // 全局变量,静态变量int默认0
int main(){
int age; // 不赋值,则默认内存的随机值
const double PI = 3.14; // const表示常量
}
tip:sizeof(long)在win中始终是4,linux中sizeof(long)为4(32位系统),为8(64位系统)
goto:
int main() {
for (size_t i = 0; i < 3; i++) {
printf("%d\n", i);
if(i == 1) goto out;
}
out:
printf("hello\n");
}
指针
int main() {
int a = 300;
int *p = &a;
printf("a = %d\n", a);
printf("p = %p\n", p);
printf("*p = %d\n", *p);
printf("p + 1 = %p\n", p+1); // 地址+4字节
int **p2 = &p; // 指向指针的指针。
printf("p2 = %p\n", p2);
printf("*p2 = %p\n", *p2); // 为p的地址
printf("**p2 = %d\n", **p2);
}
数组
int main() {
int arr[5] = {1, 2, 3, 4}; // 默认初始值为0
int *p = arr;
*p = 10; // 修改a[0] = 10
printf("*p = %d\n", *p); // a[0]值
// +1表示指向下一个元素。sizeof(int)=4,所以加4。如果是double,加8
p += 1;
printf("*p = %d\n", *p); // a[1]值
// 二维数组
int b[3][4] = {
{1, 2, 3, 4},
{1, 2, 3, 5},
{1, 2, 3, 6}
};
}
堆栈
int main() {
// 栈内存:比较小,几M ~ 几十M
int a = 1;
int b = 2;
int c = func(a,b);
// 堆内存:很大,可以申请使用
int *p = (int *)malloc(sizeof(int));
*p = 100;
printf("*p = %d", *p);
free(p); // 释放p所指空间,防止内存溢出
p = NULL; // 防止野指针。
}
函数
// Demo1: 函数声明。项目开发中,则会声明函数在头文件,实现函数则文件\库中。
int add(int a, int b); // 声明。也可以int add(int, int)
//或者,直接把实现体放到前面
int main() { }
int add(int a, int b){
return a+b;
}
// Demo2: 函数指针。项目开发中,实现一个回调函数,就把函数指针作为参数传递给另外一个函数,在此使用指针来执行此函数,比如事件处理或消息传递。
#include <stdio.h>
int add(int a, int b){
return a+b;
}
int substract(int a, int b){
return a-b;
}
typedef int (*Operation)(int, int);
int main() {
// 等效 int (*p)(int, int) = add;
Operation p = substract;
printf("%d\n", p(3,4));
}
static
void test() {
static int a = 0;
a += 1;
printf("a=%d\n", a);
}
int main() {
test(); // print a=1
test(); // print a=2
}
// static修饰全局变量和函数时:表示只能在当前文件使用,用于模块封装,防止命名冲突
string
#include <string.h> // 引入头文件
int main() {
// 字符串本身就是字符数组,也可以使用指针表示。
char a[20] = "hi"; // 等效{'h', 'i', '\0'};
char *b = "hello";
printf("%s\n", a);
printf("%s\n", b+1); // 输出:ello
// 字符串函数:strcpy\strcmp\.\strncat\strncpy\strncmp
strcat(a, b);
printf("%s\n", a);
}
结构体struct
typedef struct student {
char name[20];
int age;
float score;
}Student;
int main() {
struct student stu1 = {"Tom", 18, 60.1}; // Student stu1 =...
strcpy(stu1.name, "Tommy");
stu1.age = 19;
printf("%s, %d, %f", stu1.name, stu1.age, stu1.score);
}
共用体union
union student {
// 两个变量共用一个地址。
char name[10];
int age;
};
int main() {
union student stu1;
stu1.age = 97;
printf("%s, %d", stu1.name, stu1.age); // a, 97
}
枚举enum
enum day { // 下面的属性默认从0开始
MON,
TUE,
WED
};
int main() {
enum day day1 = TUE;
printf("%d", day1); // 1
/**
* 亦可
* enum day {
MON = 3,
TUE,
WED
};
*/
}
库引用
// a.h
#ifndef A_H // 解决库重复引用导致的重复定义问题。
#define A_H
int a = 1;
#endif
// b.h
#include "a.h"
// hello.c
#include <stdio.h>
#include "a.h"
#include "b.h"
int main() {
printf("hello %d\n", a); // 如果没有上面的条件编译。报错:重复定义
}
编译链接过程:
- 预处理:
- 头文件和条件编译、宏定义
- 除掉注释
- 编译阶段:源文件转为汇编代码
- 语法检查、类型检查
- 代码优化:常量表达式直接计算出来、删掉无用代码
- 汇编阶段:汇编代码转为机器码(目标文件
.o
) - 链接阶段:把所有目标文件使用的库文件链接起来,形成可执行文件。分为静态链接和动态链接。
- 静态链接:会将库默认直接嵌入到可执行文件中,运行时不再依赖外部库。
- 动态链接:程序运行时加载库。多个程序可以共享一个动态库,节省资源。
库:已经编译好的文件
- 静态库:
.a
(Linux中)、.lib
(win中),并不是只用于静态链接。 - 动态库:
.so
(Linux中)、.dll
(win中),并不是只用于动态链接。
有空再看:
特性 | C | C++ | C# | Objective-C | Objective-C++ |
---|---|---|---|---|---|
编程范式 | 过程化编程 | 面向对象、过程化 | 面向对象 | 面向对象 | 面向对象 + 泛型编程 |
内存管理 | 手动管理 | 手动管理 | 自动垃圾回收 | ARC | ARC + 手动管理 |
平台 | 跨平台 | 跨平台 | Windows、跨平台 | macOS、iOS | macOS、iOS + 跨平台 |
运行时 | 静态编译 | 静态编译 | 静态编译 | 动态运行时 | 动态运行时 |
模板编程 | 无 | 支持模板编程 | 无 | 无 | 支持模板编程 |
使用场景 | 操作系统、嵌入式 | 应用程序开发、游戏 | 企业应用、Web 开发 | macOS、iOS 开发 | 混合 C++ 和 Objective-C |
典型应用 | 操作系统、硬件驱动 | 高性能应用、游戏 | Web 应用、游戏开发 | iOS/macOS 应用开发 | iOS/macOS 应用开发 |
C:如果你需要控制硬件或开发底层系统,C 是最合适的选择。
C++:如果你需要高效且灵活的面向对象编程,并且涉及到复杂的数据结构或系统性能要求,C++ 更为合适。
C#:如果你开发 Windows 应用、Web 应用或跨平台应用,C# 是一个非常现代和高效的选择。
Objective-C:如果你在开发 iOS 或 macOS 应用,Objective-C 是一个必备语言,尤其是在 Swift 出现之前。
Objective-C++:如果你需要结合 C++ 的高效性和 Objective-C 的面向对象特性,尤其是在需要同时调用 C++ 库和 Objective-C 库时,可以使用 Objective-C++。
高级特性
- 如何编译makefile
- gdb调试器
- 栈溢出漏洞
编译运行机制
开发环境
常用工具
使用技巧
Makefile
构建工具make中的makfile相当于 maven中 pom.xml ,Node.js(npm) 中 package.json。
安装:
choco install make // win安装: 位置C:\ProgramData\chocolatey\bin\make.exe
sudo apt install make // linux
基本语法规则:
target: soureces
rules
...
Demo:
目前有源文件
// message.h
void message();
// message.c
#include <stdio.h>
void message() {
printf("hello world\n");
}
// hello.c
#include "message.h"
int main() {
message();
}
makefile
.PHONY: clean all
CFLAGS = -Wall -g -O2
target = hello world
object = hello.o message.o
# source = hello.c message.c
all: hello world
@echo "all done"
$(target): $(object)
gcc $(CFLAGS) $(object) -o $@
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
clean:
rm -f *.o hello
解释:
.PHONY 表明 make clean/all 后面接的是命令,而不是文件(比如有个clean文件)
CFLAGS 设置编译选项,-Wall所有警告,-g调试,-O2中度优化
$(target): $(object)
gcc $(CFLAGS) $(object) -o $@
当所需$(object)没有时,向下查找生成目标。
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
所有的c转为o: message.o 和 hello.o,
message.o: message.c
gcc $(CFLAGS) -c message.c -o message.o
makefile中自动变量:$@ 表示target; $< 表示源文件第一个参数
CMake
makefile 无需手动编写,CMake自动生成,配置文件为 CMakeLists.txt 文件
sudo apt install cmake // linux安装cmake
vs code使用cmake
- 创建CMakeLists.txt
# 常用配置。手写
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
set(SOURCES hello.c message.c)
add_executable(hello ${SOURCES})
- 执行
cmake
命令,自动识别CMakeLists.txt,并生成Makefile文件。 - 依旧执行命令:
make
自动生成可执行文件hello,清理make clean
Maven
Maven 在配置文件 pom.xml (Project Object Model)
- 管理依赖,将依赖jar和依赖的依赖jar的导入项目。手动导入依赖麻烦、可能冲突。
- 构建管理:java源文件 转为 class字节码,然后打包成可执行的jar或者war。执行 构建、打包、部署等工作。
Maven仓库:
- 本地仓库:~/.m2/repository/。本地没有则会去私服和中央仓库中查找并下载到本地,提高效率。
- 私服仓库:公司或组织的仓库,可以私用Nexus构建。非必须的
- 中央仓库:Maven官方仓库
安装:windows中,官网下载bin二进制压缩包,配置环境变量 MAVEN_HOME
和 path。mvn -v
查看版本。
# linux中安装
sudo apt install maven # 自动配置环境变量。
# 如果使用解压包,则.bashrc下
export MAVEN_HOME=../..
export PATH=$MAVEN_HOME/bin:$PATH
配置.\config\settings.xml
<!--配置本地仓库地址-->
<localRepository>D:\environment\apache-maven-3.9.6\mvn_resp</localRepository>
<!--配置中央仓库镜像,由于Maven在国内访问慢-->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
<!--配置对应jdk,可以不配-->
<profile>
<id>jdk-1.4</id>
<activation>
<jdk>1.4</jdk>
</activation>
<repositories>
<repository>
<id>jdk14</id>
<name>Repository for JDK 1.4 builds</name>
<url>http://www.myhost.com/maven/jdk14</url>
<layout>default</layout>
<snapshotPolicy>always</snapshotPolicy>
</repository>
</repositories>
</profile>
demo
Linux中创建demo:
# 创建mvn项目
mvn archetype:generate -DgroupId=net.geek -DartifactId=maven-sample -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
# 编译,target下生成class字节码
mvn compile
# 打包:maven-sample-1.0-SNAPSHOT.jar
mvn package
# 运行项目 cp:classpath。输入:Hello World!
java -cp target/maven-sample-1.0-SNAPSHOT.jar net.geek.App
IDEA中创建demo
- 依然选择maven-archetype-quickstart,然后选择GroupId,ArtifactId。即可创建成功
- 可以在IDEA的settings中修改Maven的home和配置
从IDEA中可以看到maven的各种生命周期,各种生命周期都是有对应的插件实现的,插件也就是java类,maven本质上就是通过接口调用这类来实现生命周期,而且default中生命周期有顺序的,直接执行后一个命令,会自动执行之前的命令:
- clean
- default:validate; compile; test; package; verify; install(将jar安装到本地仓库); deploy(将jar部署到公司的私服仓库);
- site:生成网站的信息和文档为静态网站。会生成index.html可以在浏览器中查看
tip:install的位置,比如D:\environment\apache-maven-3.9.6\mvn_resp\net\hour\mvn-exapmle\1.0-SNAPSHOT\mvn-exapmle-1.0-SNAPSHOT.jar。(net\hour包名、mvn-exapmle项目名、1.0-SNAPSHOT版本)
比较常用命令:
- mvn clean package
- mvn clean install
pom.xml中使用GAV(groupId artifactId version)标定一个jar包,version中snapshot (快照,开发中)和 release(开发完)
<!-- groupId不爆红说明有这个组,下面同理 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
</dependency>
<!--依赖传递: 直接依赖context,它会引用间接依赖core\aop\beans等-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.2.1</version>
</dependency>
依赖范围:
<dependencies>
<!--test: 只用于测试单元的源码,不会被正式源码引用,不会被打包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!--compile默认:编译和运行都需要-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
<scope>compile</scope>
</dependency>
<!--provided:编译需要,运行不需。比如lombok简化Setter\Getter-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
<!--servlet运行时Tomcat或其他Web容器会提供,所以也是provided-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--runtime: 运行时需要,编译无需,比如jdbc驱动-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
<scope>runtime</scope>
</dependency>
<!--system: 只能在本地电脑使用,因为源码放在git中,而git一般忽略jar,
除非其他环境手动引入这些jar
最好引入到私服仓库,其他成员只用pom即可-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/junit-3.8.1.jar</systemPath>
</dependency>
</dependencies>
父子工程:多个模块的依赖管理
- 创建maven-parent项目,同上demo。把此项目src删除。
- 在父类项目中,创建多个module,并命名为child-a、child-c、child-d、
- 可以在IDEA右侧栏中看到相应模块。
<!--maven-parent 的 pom.xml-->
<groupId>net.geek</groupId>
<artifactId>maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--pom值: 表示父类-->
<packaging>pom</packaging>
<modules>
<module>child-a</module>
<module>child-b</module>
<module>child-c</module>
</modules>
<!--child-a 的 pom.xml-->
<parent>
<groupId>net.geek</groupId>
<artifactId>maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>child-a</artifactId>
<!--表示jar,还可以war-->
<packaging>jar</packaging>
maven-parent 的 pom.xml:这样dependencies由于无条件继承,父子耦合高
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>6.2.1</spring.version>
</properties>
<!--child-* 无条件继承-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
降低耦合度:
<!--maven-parent 的 pom.xml:子类不继承-->
<!--properties 可以定义通用的属性,以便后面引用-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>6.2.1</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--child-a 的 pom.xml:继承,默认version为父类的-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
</dependencies>
依赖冲突:比如A和B,A引入D,B通过引入C再引入D?或者A和B同时引入D?D是不同的版本,到底用那个版本。
- maven本身有第一的规则:最短路径优先,先声明优先。
- 开发者:通过exclusions标签排除依赖、optional标签标记可选依赖。
spring-jdbc版本此时就会冲突,此时child-a由于路径一样,则先声明优先,使用child-b中的spring-jdbc的版本。
<!--child-a 的 pom.xml,引入child-b和 child-c -->
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-b</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-c</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--child-b 的 pom.xml-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
</dependency>
<!--child-c 的 pom.xml-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
</dependency>
如果开发者想使用child-c中的spring-jdbc版本
// 方式一:修改child-a的pom.xml,exclusions排除
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-b</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-c</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
// 方式二:修改child-b的pom.xml, optional标签为ture表示可选(非必须的 )
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
<optional>true</optional>
</dependency>
Nexus
Nexus用于私服仓库。
安装和使用:
- win中下载对应压缩包并解压,
- 通过./etc/nexus-default.properties知道端口为8081
- 开启服务
nexus.exe/run
,通过浏览器localhost:8081
访问。
Nexus网页介绍:
- 默认有maven-releases(本地hosts)、maven-snapshots(本地hosts)、maven-central(中央仓库)、maven-public(包含三者)、
- 开发者也可创建其他仓库,nexus不仅支持maven2;也支持docker,npm,yum之类的包文件
从Nexus下载:
<!-- ./conf/settings.xml 配置mirror和server -->
<mirror>
<id>maven-nexus</id>
<mirrorOf>*</mirrorOf>
<name>nexus私服</name>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
<server>
<id>maven-nexus</id>
<username>admin</username>
<password>admin</password>
</server>
上传Nexus,即deploy:
<!-- pom.xml-->
<version>1.0.0</version>
<!-- 配置nexus的id和具体仓库的url -->
<distributionManagement>
<!-- 会根据version值是否有SNAPSHOTS,自动决定是releases还是snapshots仓库 -->
<repository>
<id>maven-nexus</id>
<url>http://localhost:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-nexus</id>
<url>http://localhost:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
tip:默认不许重复上传正式版本,比如1.0.0,第二次进行deploy就会报错。
import依赖范围
Nginx
最常用的Web服务器。一个Master进程管理多个Work进程。
安装方式:
- 包管理器:linux通过apt、win通过choco、mac通过brew
- 编译安装:下载对应C语言源码,预编译、编译、安装的方式
- 使用Docker:
docker pull nginx
安装好之后,执行nginx.exe
即可启动服务,在浏览器中 localhost
即可访问,
nginx -s quit/stop
停止服务
nginx.conf为配置文件,规定了一些work数量,文件类型等。nginx -s reload
修改之后重新加载(signal)
hexo
需要装hexo,前提需安装 Node.js和 git
npm install -g hexo-cli;
hexo init blog;
cd blog;
npm install; # 安装hexo默认的依赖
hexo g; # generate 生成静态文件
hexo s; # server 本地开发服务器,通常在localhost:4000
# 此时只是hexo的服务
# 把hexo生成的blog部署的nginx:把blog/public/* 复制到nginx的html下即可。
反向代理
先安装go:choco install go
默认C:\Program Files\Go\bin
main_8000.go;然后创建内容相同的main_8001.go; main_80001.go;
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!8000")
}
func main() {
// 设置处理请求的路由
http.HandleFunc("/", handler)
// 启动服务器,监听8080端口
fmt.Println("Server is running on http://localhost:8000")
if err := http.ListenAndServe(":8000", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}
启动服务
go run main_8000.go; # 其他两个同理
# 浏览器中可以localhost:8000 访问
配置反向代理nginx.conf:通过 localhost/app
即可轮训访问8000\8001\8002,
http{
...
upstream backend {
ip_hash;
server 127.0.0.1:8000 weight=3;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
server {
...;
location /app {
proxy_pass http://backend;
}
}
...
}
负载均衡:weight=3表示大部分在此服务器;ip_hash表示在一台服务器比如只在8000,解决session互传
HTTPS配置
HTTP + SSL = HTTPS。默认http端口为80,https端口为443。一些主流的云平台可以申请到免费的ssl(Secure Sockets Layer)证书,也可以通过自签名生成证书和密钥,已经被TLS(Transport Layer Security)所取代。
安装openssl命令:choco
。默认C:\Program Files\SSL\bin
cd ssl # 创建一个ssl文件夹
#
openssl genpkey -algorithm RSA -out server.key
openssl req -new -key server.key -out server.csr # 输入对应的信息,比如国家,公司,邮箱...
openssl x509 -req -in server.csr -signkey server.key -out server.crt
nginx.config
# 解决重定向问题
server {
listen 80;
server_name localhost;
# 重定向到 HTTPS 版本
return 301 https://localhost$request_uri;
}
server {
listen 443 ssl; # 监听 443 端口,并启用 SSL
server_name localhost; # 你的域名
ssl_certificate D:/environment/nginx-1.27.3/ssl/server.crt; # 证书文件
ssl_certificate_key D:/environment/nginx-1.27.3/ssl/server.key; # 私钥文件
ssl_protocols TLSv1.2 TLSv1.3; # 推荐的 SSL/TLS 协议版本
# ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256'; # 强加密套件
ssl_prefer_server_ciphers on; # 强制使用服务器配置的加密算法
# ssl_dhparam /path/to/dhparam.pem; # Diffie-Hellman 参数,用于增加安全性,确保生成该文件(见后文)
ssl_session_cache shared:SSL:10m; # 缓存会话以提高性能
ssl_session_timeout 1d; # 设置 SSL 会话超时
# listen 80;
# server_name localhost;
#charset koi8-r;
location /app {
proxy_pass http://backend;
}
}
然后 https://localhost
虚拟机
demo1:
可以在一台服务器部署多个站点,比如一个server 就相当于一个服务器
为了方便表示nginx.conf 的 server 配置在servers/local.conf 中
# nginx.conf
http {
...;
include servers/*.conf;
}
# 新建servers/local.conf,把nginx.conf 中的server拷过来
server{
}
demo2:
npm create vite # 选择Vue和TypeScript
npm install # 安装依赖node_modules/
npm run build # 生成dist/ 下面有index.html
同样把这个网站部署到nginx上
server {
listen 5173;
server_name localhost;
location / {
root D:/environment/nginx-1.27.3/vuedemo/dist;
index index.html index.htm;
}
}
然后 https://localhost:5173
MySQL
数据库DB是按照数据结构进行组织、存储、管理数据的仓库,DBMS是数据库管理系统,常见RDBMS有MySQL
安装:
- Linux,
apt intall mysql-server
- win在官网下载安装包
docker pull mysql
windows需要进行一些配置
# 创建文件在项目下 my.init
[mysqld]
basedir=D:\environment\mysql-8.0.33-winx64\
datadir=D:\environment\mysql-8.0.33-winx64\data\
port=3306
# 输入命令
mysqld --initialize # 初始化mysql,会生成data
mysqld --install
net start mysql # 启动mysql服务
mysql -u root -p # 登陆,密码在data/*.err
alter user 'root'@'localhost' identified with mysql_native_password by 'newpassworld';
flush privileges;
常见数据库
关系型数据库:MySQL、Oracle、PostgreSQL
非关系型数据库NoSQL(No Only):Redis、mongoDB
常用命令
DDL数据库定义语言:操作数据库、表、列等,比如CREATE、DROP、ALTER、TRUNCATE
DML数据库操作语言:增删改,比如INSERT、DELETE、UPDATE、CALL
DQL数据库查询语言:查,比如SELECT
DCL数据库控制语言:访问权限和安全级别,创建用户等,比如GRANT、REVOKE
数据类型:数值、日期和时间、字符串、json、空间类型。
数值:TINYINT、SMALLINT、INT、BIGINT、FLOAT、DOUBLE
日期和时间:DATE、TIME、DATATIME、TIMESTAMP
字符串:CHAR、VARCHAR、TEXT、BLOB、、、
show databases;
use mysql;
show tables;
create database game;
drop database game;
drop table player;
CREATE TABLE play (
id INT,
name VARCHAR(100),
level INT,
exp INT,
gold DECIMAL(10,2)
)
DESC player; # 表中列的属性
# 修改表格属性
ALTER TABLE play add COLUMN last_data DATETIME; # 增加列
ALTER TABLE play DROP COLUMN last_data; # 删除列
ALTER TABLE play RENAME COLUMN name to nick_name; # 修改列的名字
ALTER TABLE play MODIFY COLUMN name VARCHAR(200); # 修改列的属性
ALTER TABLE play MODIFY level INT DEFAULT 2; # 设置默认值
# 改变表格中的数据
INSERT INTO play (id, name, level) VALUES (2, "name2", 2), (3, "name3", 3); # 插入数据
UPDATE play SET LEVEL=9 WHERE name="wangwu";
UPDATE play SET gold=3, exp=4;
DELETE from play where name="wangwu"
# 查询
SELECT * FROM player WHERE `level` > 10 AND `level` < 20 OR exp > 10 AND exp < 20
SELECT * FROM player WHERE `level` NOT in (1, 3, 5)
SELECT * FROM player WHERE `level` BETWEEN 1 AND 10;
SELECT * FROM player WHERE email is NOT NULL
SELECT * FROM player WHERE email is NULL # NULL ≠ 空字符串
SELECT * FROM player WHERE email=''
# 模糊查询
SELECT * FROM player WHERE name LIKE ‘%王%’
SELECT * FROM player WHERE name LIKE ’王_‘
SELECT * FROM player WHERE name REGEXP '王'
SELECT * FROM player WHERE name REGEXP '[王张]' # 等效 '王|张'
SELECT * FROM player WHERE name REGEXP '^王.$'
# 排序
SELECT * FROM player ORDER BY `level`
SELECT * FROM player ORDER BY `level` DESC, exp;
# 函数计算
SELECT COUNT(*) FROM player;
SELECT AVG(`level`) FROM player;
SELECT sex, COUNT(*) FROM player GROUP BY sex;
# 查询:group by分组,having组条件,order by排序
SELECT level, COUNT(*) FROM player
GROUP BY level
HAVING COUNT(`level`) > 4
ORDER BY COUNT(level) DESC
# 按姓氏数量排名
SELECT SUBSTR(name, 1, 1), COUNT(SUBSTR(name, 1, 1)) FROM player
GROUP BY SUBSTR(name, 1, 1)
HAVING COUNT(SUBSTR(name, 1, 1)) >= 5
ORDER BY COUNT(SUBSTR(name, 1, 1)) DESC
LIMIT 1,4 # 从(1,1+4]
# 去重
SELECT DISTINCT sex FROM player;
# 联表,并集Union
SELECT * FROM player WHERE level BETWEEN 1 AND 3
UNION # UNION 合并查询并去重; UNION ALL 合并所有的查询
SELECT * FROM player WHERE exp BETWEEN 1 AND 3
# 联表,交集intersect
SELECT * FROM player WHERE level BETWEEN 1 AND 3
intersect
SELECT * FROM player WHERE exp BETWEEN 1 AND 3
# 联表,取except剩下的
SELECT * FROM player WHERE level BETWEEN 1 AND 3;
except
SELECT * FROM player WHERE exp BETWEEN 1 AND 3;
# 子查询:一个select查询的结果作为另一个select的源
SELECT level, ROUND((SELECT AVG(level) FROM player)) as average,
level - ROUND((SELECT AVG(level) FROM player)) as diff
FROM player;
# 一个select结果作为另一个表的数据源
CREATE TABLE new_player SELECT * from player WHERE level < 5;
INSERT INTO new_player SELECT * from player WHERE level BETWEEN 6 AND 10;
# 是否存在相应的数据,返回0或1
SELECT EXISTS( SELECT * FROM player WHERE level > 10 )
# 表连接,INNER\LEFT\RIGTH
SELECT * from player
INNER JOIN equip
on player.id = equip.id
# 等效
SELECT * from player, equip # 笛卡尔积的内容
WHERE player.id = equip.id # 条件过滤
# index索引
create INDEX email_index on player( email)
SHOW INDEX FROM player
SELECT * from player WHERE email like "%net"
DROP INDEX email_index on player
ALTER TABLE player add INDEX email_index (email)
# view视图
# 创建view
CREATE VIEW top5 # 如果修改view,ALTER
AS
SELECT * FROM player ORDER BY level DESC LIMIT 5
UPDATE player set gold=94 WHERE id=57 # 修改表,对应view也变化
drop view top5
默认值、非空、Unique、主键约束、外键约束
Redis
商品服务和MySQL进行交互。多个商品服务都可以通过TCP/Socket,通过单线程访问远程Redis,这样就没有进程并发和切换的开销了。Redis就是一个内存中间件,存储DB的Cache,商品服务查询从MySQL中通过Key查询的Value(在java中map,则python中是dictionary)会保存到Redis中,在下次查询直接在Redis中即可,且数据类型多种比如List、Set、ZSet。如果宕机则内存丢失,一种是内存快照dump.rdb;一种是aof,提前写入命令,重写和压缩。所以名字:Remote dictionary server 远程 字典 服务 。
K-V,K为字符串。
使用:CLI(Command Line Interface)、API(Application Program Interface)、GUI
安装:apt、下载安装包
开启服务:
redis-server # 开启服务
redis-cli # 开启命令行
字符串
set name adair # del / get
keys *me
flushall
ttl name
expire name 10
setex name 10 adair # 创建键,并设置ttl
setnx name zhangsan # 键不存在则有效
# 16进制存储,看到的也是16进制。redis-cli --raw
List
lpush letter a b c # rpush
lrange letter 0 -1
rpop letter # 对应lpop
llen letter
ltrim letter 2 4 # 下标[2,4]
Set
sadd course redis mysql # sismember / srem
smembers course
# Set不可重复添加
# 拓展:交集、并集等
sinter
sunion
sdiff
SortedSet(ZSet)
zadd result 4 c 2 a 3 c
zrange result 0 -1
zrange result 0 -1 withscores
zscore result b
zrank result b
zrevrank result c
zrem result c
# 自己拓展
hash
hset person name adair
hset person age 18
hget person name
hgetall person
hdel person name
hexists person age
hkeys person;
subscribe public
# 订阅频道
subscribe geekhour;
# 另一个窗口向频道发送内容
public geekhour mysql;
Stream 消息队列,解决:发布订阅的不可持久性,无法记录消息。
# redis 5.0 才有
xadd geekhour * lang sql
xadd geekhour * course docker
xrange geekhour - +
xlen geekhour
xread count 2 block 1000 streams geekhour 1
# 在另一个端口中输入xadd geekhour 4-0 course nginx;
xread count 2 block 10000 streams geekhour $ # 此时接受geekhour的最新的消息
# 创建消费组
xgroup create geekhour group1 0 # 创建从第0个数据开始
xgroup destroy geekhour group1
xinfo groups geekhour
# 读取
xreadgroup group group1 consumer2 count 1 block 0 streams geekhour >
# 在另一个窗口写入
xadd geekhour * key value;
Geospatial
geoadd city 116.4 39.9 beijing 121.4 31.2 shanghai 114.0 22.5 shenzhen 37.0 23.1 guangzhou 120.1 30.2 hangzhou
geopos city beijing
geodist city beijing shanghai
geodist city beijing shanghai km
geosearch city frommember shanghai byradius 1000 km
HyperLogLog:高效低精度
pfadd course git mvn
pfadd course2 c java
pfmerge result course course2
pfcount result
BitMap:字符串类型的扩展
setbit demo 0 1
setbit demo 1 0
getbit demo 1
set demo "\xF0"
bitpos demo 0 # 第一个0的位置
BitField
bitfield player:1 set u8 #0 1
bitfield player:1 get u8 #0
bitfield player:1 set u32 #1 100
get player:1
bitfield player:1 incrby u32 #1 100
事务:没有关系型数据库的原子性,一个事务中命令失败之后可以继续执行下面的命令
multi # 开启事务
> set k1 v1
> set k2 v2
> exec # 执行完成
get k1
持久化:RDB(redis DB)、AOF(Append Only File)
RDB:使用快照,/etc/redis/redis.conf
AOF:写入命令的时候也会写入一个aof文件,重启redis则会重新执行这文件
# /etc/redis/redis.conf
save 3600 1 # 一小时内修改1次自动快照
appendonly yes # 开启AOF
# 查看save 保存的地址
save # 也可手动快照
config get dir # 获取配置文件
# 到指定位置,比如/var/lib/redis/dump.rdb
xxd dump.rdb # 查看文件
如果数据量比较大,save阻塞主进程,bgsave命令会fork一个子进程执行快照,但是创建fork子进程也需要时间,这段时间主进程依然不能执行其他任务
主从复制
单主节点写入,多个从节点读取,单向
# 配置文件 redis.conf,先复制一份redis_6380.conf
port 6380
pidfile /run/redis/redis-server_6380.pid
dbfilename dump_6380.rdb # 表示save/bgsave 存储的dump
replicaof 127.0.0.1 6379 # 表示父节点的port
# 启动服务
redis-server redis_6380.conf
> info replication # 查看信息
缺点:主宕机,从还需手动提升为主节点
哨兵模式
# 配置文件 sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 1
# 加载服务
redis-sentinel sentinel.conf
十大数据类型:String、List、Set、SortedSet、Hash、Stream、Geospatial、HyperLogLog、Bitmap、Bitfield、
基本概念
安装配置
常用命令
十大数据类型
事务
数据持久化
主从复制
哨兵模式
MongoDB
C++编写,NoSQL,Document存储
对应MySQL:
- 集合Collection == 表Table
- 文档Document == 行Row
- 字段Field == 列Column
- 索引index == 索引index
- _id == 主键(primary key)
- $lookup == join
- $group == group by
安装:MongoDB官网下载对应安装包,Mongosh 安装对应安装包。默认MongoDB中有Compass GUI工具
插件使用mongoDB,vs code扩展增加mongdb for vs,然后连接本地mongodb即可
use game
db.user.insertOne({name: "zhangsan"})
db.user.find()
db.user.find().limit(1)
db.user.insertOne({name: "Tom", age: "10"})
db.user.insertMany([{name: "lisi", age: "18"}, {name: "wangwu", age: "19"}])
# 有待测试
db.user.find().sort({level: 1}).limit(2).skip(1)
db.user.find({level: 3}, {name: 1, email: 0})
db.user.find({level: {$gt: 3}})
db.user.find({level: {$gte: 3, $lte: 5}})
db.user.find($and: [{level: {$gte: 3}}, {level: {$lte: 5}}])
db.user.find({level: {$in: [1-3]}}) # in 反 nin
db.user.find({email: {$exists: true}}) # 就算email: null也要返回相应的用户,因为有email字段
db.user.find({level: {$not: {$eq: 3}})
db.user.find({name: {$regex: /张/, $options: 'i'}})
db.user.countDocuments()
db.user.countDocuments({level: {$gte: 3}})
db.user.findOne({level: {$gte: 3}})
db.user.updateOne({level: 3}, {$set: {money: 100}})
db.user.deleteOne({level: 3})
基本概念
安装配置
常用命令
GUI工具
MongoShell
Docker
Docker用于build run share 应用程序的平台。CS架构,client 和 daemon 之间通过Socket 和 RESTful API进行通信。容器化:应用程序打包成容器,在容器中运行程序。
打包内容:操作系统、运行时环境、库和依赖、应用程序和环境变量、配置文件和启动命令
打包比如说MySQL、Redis、Nginx、Ubuntu之类的环境,比如一个网站:
前端Vue + 后端Springboot + DB:MySQL
需要:Node.js 环境 npm依赖、Java环境、Spring第三方库、安装MySQL、环境变量和启动脚本
还可能需要:Redis缓存、Nginx负载均衡、各种微服务、
如果在开发环境中运行成功,在测试环境不一定成功。
docker持久化:由于docker容器重启之后会丢失之前的数据,docker会将数据映射到宿主机的逻辑卷中
虚拟机:物理机 + Hypervisor + n个虚拟器
Docker:物理机 + Docker + n个容器
安装:下载docker安装即可
# 配置镜像
"registry-mirrors": [
"https://docker.1panel.live",
...
]
demo
流程:
- 编写Dockerfile
- 创建镜像
- 启动容器
创建Dockerfile
FROM node:14-alphine
COPY index.js /index.js
CMD node /index.js
创建镜像 并 启动镜像
docker build -t hello-docker .
docker images
docker run hello-docker
# 比如pull,然后运行up主的镜像
docker pull geekhour/hello-docker
docker run geekhour/hello-docker
docker compose
多容器docker、通过docker-compose.yaml配置、一条命令创建并启动所有服务
docker compose up
基本概念
安装配置
常用命令
构建镜像
运行容器
docker compose & Kubernetes
Kubernetes
容器少可以用脚本,上百容器可以使用k8s。Google开源
Pod:k8s调用最小单元;创建一个环境,多个容器共享资源,比如网络、存储、配置。通常一个pod配置一个容器,多个容器比如主容器和辅助容器,sidercar用于服务监控和日志。pod之间通过ip进行访问
Node:一个物理机或者虚拟机
Pod:最小单位,由一或多个容器构成
Service:一系列Pod组成的服务
Ingress:Service的入口
ConfigMap:配置信息
Secret:配置敏感信息
Volumes:存储,防止DB丢失现有的信息
Deployment:多个app形成副本
StatefulSet:保证多个数据库信息同样
demo
本地搭建集群k3s,也可以使用minikube
multipass launch --name k3s --cpus 2 --memory 8G --disk 10G
multipass launch --name worker1 --cpus 2 --memory 8G --disk 10G
multipass launch --name worker2 --cpus 2 --memory 8G --disk 10G
# 进入k3s
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
sudo kubectl get nodes
# 退出到linux
TOKEN=$(multipass exec k3s sudo cat /var/lib/rancher/k3s/server/node-token)
MASTER_IP=$(multipass info k3s | grep IPv4 | awk '{print $2}')
for f in 1 2; do
multipass exec worker$f -- bash -c "curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_URL=\"https://$MASTER_IP:6443\" K3S_TOKEN=\"$TOKEN\" sh -"
done
# 再次进入k3s,可以看到集群成功
sudo kubectl get nodes/pod/svr
在线集群网站:https://killercoda.com
kubectl
sudo kubectl run nginx --image=nginx
sudo kubectl get pod
sudo kubectl create deployment nginx-deployment --image=nginx
sudo kubectl get deployment
sudo kubectl get replicaset
开发测试运维架构
基本概念
架构原理
核心组件
资源对象
环境配置
demo
堡垒机
Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。java在jre环境运行,js在nodejs环境运行
- 异步和事件驱动:非阻塞 I/O 模型,适用于大量并发
- 单线程
- 模块化,内置模块(fs、http、path)
安装:
- 下载Node.js安装包到environment\目录下。
node -v | npm -v
测试 - 目录下创建文件夹node_cache,node_global。默认
npm config set prefix "...\Nodejs\node_global"
npm config set cache "...\Nodejs\node_cache"
npm config get registry # 配置国内镜像
npm config get prefix
npm config list
- 系统变量,NODE_PATH为…\Nodejs\node_global\node_modules。并在PATH中添加%NODE_PATH%
- 用户变量,…\AppData\Roaming\npm修改为…\Nodejs\node_global
- 测试:
npm install express -g
安装在\node_global\node_modules\express
Multipass
简单轻量安装ubuntu。
# 创建虚拟器
multipass launch --name myubuntu # --cpus 2 --memory 8G --disk 10G
multipass start/shell/stop myubuntu
multipass list/help
multipass exec myubuntu -- ls -l # 执行命令
# 默认不许ssh,修改
multipass shell myubuntu
sudo apt install net-tools
vim /etc/ssh/sshd_config # PasswordAuthentication yes,PermitRootLogin yes
sudo service ssh restart
passwd
ssh-keygen -t rsa -b 4096
ssh-copy-id ubuntu@192.168.105.10
alias myubuntu='ssh ubuntu@192.168.105.10'
Service种类:
- ClusterIP:默认,集群内部
- NodePort:节点端口,公开
- LoadBalance:服务公开到外部负载均衡器上
- ExtralName:将服务映射到外部域名上
- Headless:DNS解析和服务发现
问题
Linux安装出现
zql@adair-pc:~$ sudo apt install multipass
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
No apt package "multipass", but there is a snap with that name.
Try "snap install multipass"
E: Unable to locate package multipass
解决:
# 其一
sudo snap install multipass
# 其二
sudo add-apt-repository ppa:canonical-server/multipass
sudo apt update
sudo apt install multipass
Windows
命令
tasklist | findstr "nginx" # 查找任务
taskkill /f /t /im nginx.exe # 终止任务,f强制,t递归子进程,im映像名称
# net命令:网络和系统管理
net stop nginx # 先停止系统的nginx服务,否则停止nginx,也会重新启动
# netstat:查看端口
netstat -ano # a:all n:number o:pid
常见问题
端口占用
# 8080 端口被占用
netstat -ano | findstr "8080" # 查找端口对应的pid(1234)
tasklist | findstr "1234" # 根据pid找到任务,
# 终止任务
tasklist /f /t /pid 1234
tasklist /f /t /im demo.task
常识
局域网:
- 192.168.
- 172.16 ~ 172.32
- 10.j