最近对我的个人博客进行了全面的重构。由于旧项目还停留在 2018 年的状态,为了让它更符合现代开发习惯,我将其从本地手动维护升级到了基于 GitHub Actions 的自动化部署体系。

以下是本次重构的关键流程记录。

1. 核心架构升级

  • 框架: 继续沿用成熟的 Hexo 静态博客框架。
  • 主题: 采用经典的 NexT 主题(Mist 方案),并开启了全站深色模式支持。
  • 包管理: 全面转向 pnpm,提升依赖安装速度并优化本地磁盘空间。

2. 功能重构与增强

导航与结构

  • 重新配置了菜单系统,启用了 首页关于标签分类归档
  • 手动补全了 tagscategories 的页面索引文件,确保导航不失效。
  • 引入了 hexo-generator-searchdb 插件。
  • 在主题配置中开启了实时本地搜索功能,现在可以通过关键词快速检索历史文章。

3. 自动化部署 (CI/CD) 流程

这是本次重构最核心的部分。我利用 GitHub Actions 实现了“提交即发布”的流程。

部署脚本配置

.github/workflows/deploy.yml 中定义了以下步骤:

  1. 环境准备: 使用 Node.js 20 和 pnpm 环境。
  2. 构建项目: 执行 pnpm run build 生成静态文件。
  3. 自动传输: 通过 appleboy/scp-action 插件,利用 SSH Key 将生成的 public/ 目录内容同步到生产服务器。

安全管理 (Secrets)

为了保护敏感信息,服务器的登录凭证(IP、用户名、私钥、目标路径)全部托管在 GitHub 仓库的 Secrets 中,避免了明文泄露的风险。

4. 结语

通过这次重构,博客不再只是一个本地的文件夹,而是一个拥有自动化流转能力的现代化项目。

如果你也想访问我的新版博客,可以通过以下地址:
blog.mineclaw.top

访问提示: 确保服务器已开启 80 (HTTP) 和 443 (HTTPS) 端口。

vim

编辑

1
2
3
4
v 选中
j k ctr+d ctr+u ctr+f ctr+b
vim -b $fileName(二进制打开文件)可看到^M :%s/\r//g 替换命令替换
u 在命令行模式下是撤销操作

替换

1 2 3 4 5 6 7 8 9 9,%s/cur7/cur6/g 从第9行开始替换 :%s/cur7/cur6/g :s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky n 为数字,若 n 为 .,表示从当前行开始到最后一行: :n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第一个 vivian 为 sky :n,$s/vivian/sky/g 替换第 n 行开始到最后一行中每一行所有 vivian 为 sky :%s/vivian/sky/(等同于 :g/vivian/s/sky/) 替换每一行的第一个 vivian 为 sky :%s/vivian/sky/g(等同于 :g/vivian/s/sky/g) 替换每一行中所有 vivian 为 sky

转义:可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符

1 2 :s#vivian/#sky/# 替换当前行第一个 vivian/ 为 sky/ :%s+/oradata/apras/+/user01/apras1+ (使用+ 来 替换 / ): /oradata/apras/替换成/user01/apras1/

awk

1 2 3 4 awk [-F field-separator] 'commands' input-file(s) 其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。 通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。

以 ‘,’ 为分隔符,统计$3的计数数据:

1 ``` awk -F ‘,’ ‘{arr[$3]+=1}END{for(i in arr)print i,arr[i]}’ temp1

计算最大最小平均值:

1 2 3 4 5 awk '{arr[$1]++}END{for(i in arr) { if(arr[i]>=50) print i,arr[i]; fi}}' awk '{sum+=$1} END {print "Sum = ", sum}' awk '{sum+=$1} END {print "Average = ", sum/NR}' awk 'BEGIN {max = 0} {if ($1>max) max=$1 fi} END {print "Max=", max}' awk 'BEGIN {min = 1999999} {if ($1<min) min=$1 fi} END {print "Min=", min}'

执行sql

1 2 3 4 5 6 db_r="mysql -h $dbhost -udev -$pwd -e" ret=`$db_r"$sql" --skip-column-name` for id in $ret do echo $id done

函数

1 2 3 4 5 function f(){ echo a } f 0 CLICK today_click_c=$?

函数返回值在调用该函数后通过$? 来获得。

注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

if

判断文件是否存在

1 2 3 if [ ! -f "$PATH" ];then rm /home/jun.yu/earningMoney/d1/*$delday* fi
1 2 3 ``` if [ `ls -l $path*/

判断字符串是否为空

1 2 3 if [ ! -z "$PATH" ];then PATH="/home/jun.yu/earningMoney/d1/*$delday*" fi

循环

1 2 3 4 for i in $(seq 0 3) do echo "adsource:"$i done

写作目的

最近读了《高性能MySQL_第3版(中文)》决定写一篇专门的博客来记录所学所得,以及记录自己平时的积累经验,并传播给大家。

存储引擎

MyISAM

单独存放行数信息(count(*)不带筛选条件时不用读表);
支持表锁,不支持行锁;
不支持事务;
对于blob以及text长字段也可以基于前500个字符加索引;
可以设置延迟更新索引;
仅有此类型支持地理空间搜索

InnoDB

支持表锁和行锁;
四个隔离级别(未提交读(READ UNCOMMITTED),提交读(READ COMMITTED),可重复读(REPEATABLE READ)(默认),可串行(SERIALIZABLE),关于锁和事务有更详细的文档:美团技术博客-Innodb中的事务隔离级别和锁的关系);
聚簇索引,二级索引(非主键索引)必须包含主键索引;

索引

索引类型

1
2
3
4
5
6
7
8
9
10
11
12
13
    B-Tree索引
(树形结构,只有两层节点,子节点之间有指向后面节点的指针):
按照左前缀原则,从最左列开始查找;
不能跳过前面的索引,即联合索引只能从第一列开始索引;
如果从某列是按照范围查询,则后面的列都无法使用索引查找,例如between
哈希索引:
只有精确匹配索引搜有的列的查询才有效(因为是计算hash值);
不存储字段值;
哈希索引不是按照索引值排序的,所以无法用于排序;
不支持部分索引;
只支持等值索引,即=,!=,IN(),也不支持范围查询比如>;
哈希非常快,除非很多冲突;
选择性很低的列建立哈希索引,冲突很多,性能影响极大

索引策略

  1. 独立的列,不能是表达式的一部分,也不能是函数,如column+3=4;
  2. 前缀索引,当索引的列很长时可以模拟hash索引,或者选取部分字符作为索引,减少索引空间,而且尽量选择重复性低的字符,对于blob text 或者很长的varchar必须使用前缀索引,缺点是无法使用前缀索引order by 和group by,也无法使用前缀索引做覆盖扫描
  3. 聚簇索引,不是一种索引类型,而是一种数据存储方式,叶子页包含了行的全部数据,但是节点页只包含了索引列,访问数据更快,使用覆盖索引时可以直接使用页节点的主键值,更新索引的代价很高,插入新行或者更新导致移动行时导致”页分裂”,页分裂将导致占用更多的磁盘空间,聚簇索引可能导致全表扫描变慢,尤其当行比较稀疏或者由于页分裂导致数据存储不连续时,二级索引的叶子节点包含引用行的主键列,且二级索引访问需要两次索引查找,因为存放的是”行指针”
  4. 覆盖索引,如果一个索引包含(覆盖)所有需要查询的字段的值,这个索引被称为覆盖索引

mysql schema和数据类型优化

  1. 数据类型越小越好(载入内存以及存储空间),不要用NULL,如果为NULL,mysql自身优化会很麻烦,带来不必要的开销
  2. varchar和char,varchar更新时容易产生分裂页的问题,varchar(10)实际需要11的存储空间(1字节用于存储长度,<=255用1个字节),varchar适用于:字符串最大长度比平均长度大很多;更新少;使用UTF-8类似的复杂字符集,每个字符使用不同的字节数存储;
  3. blob和text,当值太大时InnoDB会使用存储指针的方式存储,blob是二进制数据没有排序规则和字符集,text有字符集和排序规则,排序时只对max_sort_length做排序(或者使用ORDER BY SUBSTRING(column,length))
  4. 使用枚举代替字符串,枚举实际存储的是整数
  5. 时间类型 DATETIME-存储的是YYYYMMDDHHMMSS的整数,TIMESTAMP-存储的是从1970年1月1日午夜来的秒数(只用4个字节)
  6. BIT 类型是字符类型 ‘0’=48 实际是ASII码值;SET类型无法通过索引查找,存储整数,按位炒作
  7. 特殊类型 低于秒精度的时间错使用bigint,IPv4用无符号整数存储 INET_ATON()和INET_NTOA()函数做转换
  8. double 数据类型 格式 DOUBLE(M,D)M的含义是整个数的长度,数字长度,D是精度,几位小数

其他积累经验

  1. 转换成字符串时,空格会被忽略,而java中不会忽略,例如在数据库中是 “ abc”,在select where 条件中筛选 “abc” 会被筛出来,而在Java中再去匹配则会产生不相等问题
  2. where 条件中not in范围筛选可用关联替换表,然后关联字段 is null 用于等效筛选
  3. 时间格式化函数 DATE_FORMAT(createtime,”%Y%m%d %H:%i:%s”)
  4. GROUP_CONTACT()聚合函数,分组之后连接字符串
  5. 设置字符区分大小写: 字符集中_ci后缀–不区分大小写(character ignore),_bin后缀–二进制比对,_cs后缀–区分大小写(character sense)
  6. 查询后插入 insert into table1(item1,item2,…) select item1,item2,… from table2
  7. ORDER BY FIELD(column, 2, 0) DESC,ctime DESC
  8. FIND_IN_SET(column,’value1’)
  9. 表关联顺序由优化器决定,并不是指定的顺序,将外链接转化成内连接
  10. 没必要返回所有的字段
  11. IN() MySQL会事先做排序,然后二分法查找,当条目很多时用IN()
  12. mysql 索引原理:使用B+树 MyISAM 引擎使用过节点存储地址信息;InnoDB引擎使用节点储存数据,叶节点包含了完整的数据记录,因为InnoDB的数据文件本身要按主键聚集,辅助索引data域存储相应记录主键的值而不是地址,用非单调的字段作为主键在InnoDB中不是个好主意
  13. 优化sql:最前缀原则-联合索引(a,b,c)先匹配a,再匹配b,再匹配c,但是order by和group by时失效(需要进行全字段匹配或者前匹配。也就是=‘xxx’ 或者 like ‘xxx%’)
  14. 尽量的扩展索引,不要新建索引,因为索引建立太多会影响插入和删除的操作
  15. 查询where条件数据类型不匹配也无法使用索引
  16. 对于like查询,”%”不要放在前面
  17. 字符串与数字比较索引使用不到
  18. last_insert_id()与每个连接相关,由MySQL server来维护的,由每条连接维护独立的值,某条连接调用last_insert_id()获取到的值是这条连接最近一次insert操作执行后的自增值,该值不会被其它连接的sql语句所影响。
    19.事务开启时,插入的数据不会被其他事务读到,事务级别至少是提交读

红黑树

性质

  1. 颜色:所有节点非黑即红,根节点是黑色,红色节点的父节点是黑色,每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的
  2. 平衡树:左边节点<根节点<右边节点,没有节点相同的点
  3. 树深度:每个节点到叶子节点的黑色节点数相同

证明树的高度O(lgn)

  1. 归纳法证明(略)
  2. 首先将所有红色的节点向上收到黑色的父节点,得到一棵高度为黑色节点高度的(bh)的树(由性质3可以得出),经过收敛得到一棵2-3-4树,即每个节点所含有的原有的节点数为2/3/4,则原有n+1个叶子节点,则 2^bh<=n+1<=4^bh bn<=lg(n+1)<=2bh,则bh<=log(n+1),即输的黑色高度不超过log(n+1),而原树的节点为红黑相间,且一条根节点到叶子节点上,红色节点数不超过一半(颜色性质),则h<=2bh<=2log(n+1),得证

旋转

当数据更新时,红黑树不满足基本性质时,需要做旋转操作:

红黑树更新(插入/删除)

插入新节点时,默认上色为红色,当颜色不合适时,重新上色或者旋转

  1. 不需要作调整(插入的红节点刚好在黑色节点下)(color[p[new]]=black)
  2. 插入的红色节点父节点是红色color[p[new]]=red,假设插入节点的父亲是祖父节点的左孩子(右孩子相反)即 p[new]=lchild[p[p[new]]]
    • case1. 叔节点是红色 color[rchild[p[p[new]]]]=red
      解决方案:重新上色,color[p[new]]=black,color[rchild[p[p[new]]]]=black,color[p[p[new]]=red
    • case2. 叔节点是黑色 color[rchild[p[p[new]]]]=black 插入节点是左孩子,对祖父节点作右旋,并将祖父节点上色为红色,父节点上色为黑色
    • case3. 叔节点是黑色 color[rchild[p[p[new]]]]=black插入节点是右孩子,对父点作左旋,转换成case2

图示说明:

Tomcat日志问题:

  • 问题描述:在apache下载tomcat到服务器运行,发现生成日志文件只有root用户有读写权限,普通用户无读权限,即生成文件权限为640.

  • 问题解决办法:在tomcat 的bin/catalina.sh 中配置UMASK字段,即配置文件生成的默认权限的掩码.

    maven scope问题

  • compile,缺省值,适用于所有阶段,会随着项目一起发布。

  • provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。

  • runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。

  • test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。

  • system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它

跳跃表介绍

如图:
image
生成跳跃表时,随机抛硬币,正面向上跃迁一级,每一级都做相同处理。
查找速度在O(logn)时间复杂度的动态数据结构。
具有实现简单的有点,因为是链表的结构。
术语:具有高概率是O(logn)。

概率:

1 P = 1-O(1/(n^α))(α≥1)

证明:
引入概念布尔不等式:指对于全部事件的概率总和不大于单个事件的概率总和。
跳跃表的层数为O(logn)的概率为:
P{level>clogn}≤n*P{X|X为单个元素提升clogn次}=n*(1/2)^clogn = 1/n^(c-1) 令α=c-1 α≥1 。
那么层数至多为clogn的概率是1-1/n^α,α可以去特别大,层数为clogn的概率将会很高。
在搜索时,从要查找的数据出发回到起点,总的向上移动的次数至多为clogn,而总的移动次数小于等于出现clogn次数的抛硬币次数,即为搜索的时间复杂度。证明从查找数据点回到起点所抛硬币,出现clogn次正面的抛硬币次数为O(logn)的概率为1-1/n^α。
假设总共抛硬币的次数为10clogn,求P{出现至多为clogn次正面},P≤C(10clogn,clogn)*(1/2)^(10clogn-clogn)
因为C(y,x)≤(ey/x)^x
P≤(10e)^clogn/ 2^9clogn= 2^(log10e-9)clogn =(1/2^(9-log10e)clogn) 令(9-log10e)c=α,P≤1/2^αlogn =1/n^α

跳跃表实现

跳跃表实际实际运用

跳跃表和红黑树对比

跳跃表其实也是一棵树,等效的数,但是维护简单,没有红黑树那么多的旋转上色,而且也是具有随机性,在数据越多的时候,性能越接近O(logn)

0%