# 更多

# Git 提交规约

# 格式

<type>[scope]: <subject>
// 空一行
[body]
// 空一行
[footer]

注:[]代表可选,<>代表必选。

# type

必填,用于指定 commit 的类型。

feat:增加新功能
fix:修复 bug
docs:只改动了文档相关的内容
style:格式修改,没有修改代码逻辑,比如格式化、换行等
refactor:重构代码,既没有新增功能,也没有修复 bug,比如提取某段代码为一个方法、重构某个功能等
perf:性能、体验优化等
test:新增 test 用例或修改现有测试用例
build:构造工具的或者外部依赖的改动,比如 maven
ci:与 CI(持续集成服务)有关的改动
chore:不修改 src 或者 test 的其余修改,例如构建过程或辅助工具的变动
revert:执行 git revert 打印的 message

当同时有feat、fix和其他类型时,类型取feat、fix。

# scope

非必填,用于描述改动的范围,格式一般为项目名/模块名,如果一次 commit 修改多个模块,建议拆分成多次 commit,以便更好追踪和维护。

# subject

必填,此次提交的简短描述,动词开头,第一人称现在时,比如add,而不用 added、adds,第一个字母小写,句尾不加句号(.)

# body

非必填,此次提交的详细描述,主要描述改动之前的情况及修改动机,对于小的修改不作要求,但是重大需求、更新等必须添加body来作说明。

footer只用于以下两种情况

  • break changes

break changes 指明是否产生了破坏性修改,涉及 break changes 的改动必须指明该项,类似版本升级、接口参数减少、接口删除、迁移等,以BREAKING CHANGE:开头,后面是变动的描述、变动的理由以及迁移的方法。

  • 关闭 issue

当前提交修改了某个 issue

# 示例

fix(ngStyle): correctly remove old style when new style value is invalid

Since d6098ee, old styles were not removed if `newStyles` specified an
invalid value for the style (e.g. `false`). The assumption was that the
new style would overwrite the old style value, but using an invalid
value made browsers ignore the new value and thus keep the old style.
This would typically happen when guarding a style with a boolean flag;
e.g.: `ng-style="{backgroundColor: isError && 'red'}"`

This commit essentially revers commit d6098ee, whose main purpose was
to work around jquery/jquery#4185. The jQuery issue has been fixed in
3.4.0, so that should not be a problem any more.

Fixes #16860

Closes #16868

# Java 代码格式

Java 代码格式在遵循 Google Java Style Guide (opens new window) 的基础上,采用 Alibaba4个空格缩进的规约(谷歌默认采用的是2个空格的缩进)。

IntelliJ IDEA 中导入(Preferences -> Editor -> Code Style -> Java -> Schema -> Import Schema)以下格式文件:

<?xml version="1.0" encoding="UTF-8"?>
<code_scheme name="GoogleStyle">

    <codeStyleSettings language="JAVA">
        <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false"/>
        <option name="KEEP_BLANK_LINES_IN_CODE" value="1"/>
        <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1"/>
        <option name="ALIGN_MULTILINE_PARAMETERS" value="false"/>
        <option name="ALIGN_MULTILINE_RESOURCES" value="false"/>
        <option name="ALIGN_MULTILINE_FOR" value="false"/>
        <option name="CALL_PARAMETERS_WRAP" value="1"/>
        <option name="METHOD_PARAMETERS_WRAP" value="1"/>
        <option name="EXTENDS_LIST_WRAP" value="1"/>
        <option name="THROWS_KEYWORD_WRAP" value="1"/>
        <option name="METHOD_CALL_CHAIN_WRAP" value="1"/>
        <option name="BINARY_OPERATION_WRAP" value="1"/>
        <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true"/>
        <option name="TERNARY_OPERATION_WRAP" value="1"/>
        <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true"/>
        <option name="FOR_STATEMENT_WRAP" value="1"/>
        <option name="ARRAY_INITIALIZER_WRAP" value="1"/>
        <option name="WRAP_COMMENTS" value="true"/>
        <option name="IF_BRACE_FORCE" value="3"/>
        <option name="DOWHILE_BRACE_FORCE" value="3"/>
        <option name="WHILE_BRACE_FORCE" value="3"/>
        <option name="FOR_BRACE_FORCE" value="3"/>
        <option name="PARENT_SETTINGS_INSTALLED" value="true"/>
        <indentOptions>
            <option name="INDENT_SIZE" value="4"/>
            <option name="CONTINUATION_INDENT_SIZE" value="4"/>
            <option name="TAB_SIZE" value="4"/>
        </indentOptions>
    </codeStyleSettings>

</code_scheme>

# 接口调试利器 EasyYapi 插件

IntelliJ IDEA 的 EasyYapi 插件是一个基于 javadoc & KDoc & ScalaDoc 解析 API 文档的插件,可以在保持代码零侵入的情况下得到相当完整的 api 文档(特殊的需求还是需要部分特殊的注释/注解配合),支持导出文件中的 API 到yapi/postman/markdown,以及在 IDEA 中直接发起文件中的 API 请求进行接口调试

如果是 Spring 项目,我们可以选中一个或多个 @Controller.java 文件来批量生成需要调试的接口,效果如下:

首先,我们需要在 IntelliJ IDEA 的插件市场中搜索并安装 EasyYapi 插件,安装成功后需要重启 IDEA:

然后,选中需要调试的 API 文件,鼠标右键选择Call Api即可打开接口调试窗口对选中文件中的 API 发起请求进行接口调试。打开调试窗口后,我们选中用户登录接口,如下所示:

从上图可以看出,接口请求路径和请求数据格式都已经自动生成好了,我们只需要修改调试数据,然后点击运行按钮来发起 API 请求:

如果我们要导出文件中的 API 到 Yapi/Postman/Markdown,需要选中一个或多个 @Controller.java 文件然后鼠标右键选择Export Api(也可以直接选择Export Yapi/Export Postman/Export Markdown),如下所示:

生成的MarkdownAPI 文档效果如下:

# MySQL 官方多线程逻辑备份工具

# 介绍

MySQL Shell (opens new window)是 MySQL 的高级命令行客户端和代码编辑器。除了 SQL,MySQL Shell 还为 JavaScript 和 Python 提供脚本功能。当 MySQL Shell 通过 X 协议连接到 MySQL 服务器时,X DevAPI 可用于处理关系数据和文档数据。

MySQL Shell 8.0.21 包括一些新的易用、高性能和集成的工具(MySQL Shell Dump & Dump Loading Utility)用来创建逻辑转储和执行逻辑还原。该序列工具以 MySQL Shell 8.0.17 中引入的多线程 CSV 导入工具 util.importTable() 为基础构建以便轻松转储和加载整个数据库实例或一组 schema。该序列工具包括:

  • util.dumpInstance():转储整个数据库实例,包括用户

  • util.dumpSchemas():转储一组数据库 schema

  • util.loadDump():将转储加载到目标数据库中

主要特色功能包括:

  • 多线程转储,将较大的表分成较小的块,速度高达 3GB / s

  • 并行加载块,结合 MySQL Server 8.0.21 中的禁用 InnoDB Redo Log 的功能,加载性能可以超过 200MB / s

  • 在转储的同时进行加载

  • 中断后继续加载数据(断点续传)

  • 内置压缩(zstd 和 gzip)

  • 加载数据后推迟二级索引的创建

  • 直接从 OCI 对象存储中转储和加载

  • 兼容 OCI 的 MySQL 数据库服务模式,使得向云的迁移变得容易

# MySQL Shell 安装

MySQL Shell 提供了 Windows、Linux 和 Mac 的安装支持,具体请查看如下的官方安装文档:

https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-install.html (opens new window)

# Dump & Dump Loading Utility

MySQL Shell Dump & Dump Loading Utility 的使用以及与其它各种主流逻辑转储和加载工具 mysqldump,、mysqlpump 和 mydumper 的比较结果如下:

  • 数据以大约 256 MB 的块形式转储
mysqlsh-js> util.dumpSchemas(["<db>"], 
                             "<directory>",
                             {threads: 88, 
                             bytesPerChunk: "256M"})

转存

  • 加载
mysqlsh-js> util.loadDump("<directory>", 
                          {threads: 88})

加载

Redo Log 禁用的情况下,MySQL Shell 能够快速转储数据,高达近 3GB/s,并以 200MB/s 以上的速度加载数据。

# 参考

[1] https://dev.mysql.com/blog-archive/mysql-shell-dump-load-part-1-demo (opens new window)

[2] https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-utilities-dump-instance-schema.html (opens new window)

[3] https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-utilities-load-dump.html (opens new window)

# Shell 基础操作

在计算机科学中,Shell 俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(command interpreter,命令解析器),它接收用户命令,然后调用相应的应用程序。

Shell 同时也是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。

在 Linux/Unix 平台上,Shell 一般默认为 Bash Shell,也有其他 Shell,比如 C Shell 等;Mac 平台,从 Catalina 版本开始,默认 Shell 从 Bash 改为 Zsh;Windows 平台上,Shell = CMD(Command Shell 的简写,也叫做命令提示符)。

Mac 平台通过 terminal.app、Windows 平台通过 cmd.exe 来运行 shell。

在 Linux/Mac 上,通过如下命令查看当前系统所有的 shell:

cat /etc/shells

结果如下:

# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

查看当前使用的 shell:

echo $0

结果如下:

-zsh

修改系统默认 shell 为 bash:

chsh -s /bin/bash

查看结果(需要重启终端):

xiongxiangdeAir:~ xiongxiaoyang$ echo $0
-bash

# 切换目录

无论是 Linux 平台、Mac 平台还是 Windows 平台,都是通过 cd+目录名进入目录, cd ..返回上级目录。我们还可以通过pushd+目录名进入新目录同时记住之前的目录名,之后可以使用 popd 返回之前的目录。

xiongxiaoyang@xiongxiangdeAir ~ % pushd java/novel
~/java/novel ~
xiongxiaoyang@xiongxiangdeAir novel % popd
~
xiongxiaoyang@xiongxiangdeAir ~ % 

# 目录列表

Linux/Mac 平台通过ls命令查看当前目录下的所有文件和子目录,Windows 平台通过dir命令查看。可以使用通配符*对显示的内容进行过滤。

xiongxiaoyang@xiongxiangdeAir manager % ls *Cache*.java
AuthorInfoCacheManager.java	BookRankCacheManager.java
BookCategoryCacheManager.java	FriendLinkCacheManager.java
BookChapterCacheManager.java	HomeBookCacheManager.java
BookContentCacheManager.java	NewsCacheManager.java
BookInfoCacheManager.java	UserInfoCacheManager.java

# 新建目录

Linux/Mac 平台通过mkdir命令新建目录,Windows 平台通过md命令新建目录。

# 删除文件

Linux/Mac 平台通过rm+文件名删除文件,Windows 平台通过del+文件名删除文件。

# 删除目录

Linux/Mac 平台通过rm -r命令删除目录及其包含的所有文件,Windows 平台通过deltree命令实现。

# 重复命令

所有平台都可以通过⬆️键来显示上一条命令,Linux/Mac 平台可以通过!!来执行上一条命令,!n来执行第 n 条命令。

# 命令历史

Linux/Mac 平台通过 history命令来查看所有使用过的命令,Windows 平台通过F7键来实现。Linux/Mac 平台还会显示历史序号,这样就可以通过上面的!n命令来方便重复执行。

xiongxiaoyang@xiongxiangdeAir bin % history
  992  ls
  993  cd front
  994  ls
  995  cd ../../manager
  996  ls
  997  ls *Cache*.java
  998  chsh -s /bin/bash
  999  echo $0
 1000  echo $0
 1001  cd java/novel-plus/novel-front/target/build/bin
 1002  start.sh
 1003  ls
 1004  ll
 1005  chsh -s /bin/bash
 1006  ls
 1007  ll

xiongxiaoyang@xiongxiangdeAir bin % !1006
ls
readme.txt		stop.sh
start.sh		windows-start.bat

# 解压文件

Linux/Mac 平台通过unzip命令来解压.zip后缀的压缩包文件,Windows 平台需要通过互联网安装unzip命令。

...

更多 shell 命令请搜索 Windows ShellBash Shell

# Integer.valueOf() 的享元模式应用

在 Java 中,如果我们想要创建一个 Integer 对象,一般有以下三种方式:

  1. 通过标准对象创建语法 new Interger(int) 来创建

  2. 通过静态工厂 Integer.valueOf(int) 来创建

  3. 通过自动装箱将基本类型 int 自动转换为包装类型 Integer,这其实是通过对 Integer.valueOf() 的自动调用来完成的

方式 1 和方式 3 本质上没有什么区别,只不过方式 1 看起来更简洁,那么方式 1 和方式 2 有什么区别呢?先来看一个经典的面试题:

public static void main(String[] args) { 
    Integer m = Integer.valueOf(111);  
    Integer n = Integer.valueOf(111);  
    System.out.println(m == n);

    m = new Integer(111);  
    n = new Integer(111);  
    System.out.println(m == n);   
  
    Integer i = Integer.valueOf(222);    
    Integer j = Integer.valueOf(222);   
    System.out.println(i == j);
   
    i = new Integer(222);  
    j = new Integer(222);   
    System.out.println(i == j);
}

大家可以不急着看答案,先独立思考一下以上的打印结果。我想刷过面试题的同学答对这道题应该问题不大,并且能够知道一些原因。但是真正深入了解源码,以及背后设计思想的同学应该也不是很多。我们先来看看构造函数 Interger(int) 的源码(JDK 17),如下所示:

private final int value;
@Deprecated(since="9", forRemoval = true)
public Integer(int value) {
    this.value = value;
}

使用 new 关键字创建对象会自动调用该对象的相应构造函数,从以上源码中可以看出,Interger(int) 构造函数只做一件事,那就是初始化成员常量 value 的值,该常量代表了 Integer 对象的值。

使用 new 关键字每次都会在堆内存上开辟一块新的空间用于存放创建出来的对象,只要使用了 new 关键字那么创建出来的对象就是新的对象,而 == 关系操作符比较的是两个对象之间的引用是否相等(即是否引用了同一个对象),所以使用 new 创建的每一个 Integer 对象使用== 关系操作符得到的结果都是false

我们再来看看静态工厂 Integer.valueOf(int) 的源码(JDK 17),如下所示:

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer[] cache;
    static Integer[] archivedCache;

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                h = Math.max(parseInt(integerCacheHighPropValue), 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        // Load IntegerCache.archivedCache from archive, if possible
        CDS.initializeFromArchive(IntegerCache.class);
        int size = (high - low) + 1;

        // Use the archived cache if it exists and is large enough
        if (archivedCache == null || size > archivedCache.length) {
            Integer[] c = new Integer[size];
            int j = low;
            for(int i = 0; i < c.length; i++) {
                c[i] = new Integer(j++);
            }
            archivedCache = c;
        }
        cache = archivedCache;
        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}
@IntrinsicCandidate
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

从以上源码可以看出,Integer 类中包含一个私有的静态类 IntegerCache,该类是一个 Integer 对象数组(默认 -128 ~ 127)的缓存,缓存在第一次使用时被初始化,缓存的大小(Integer 缓存对象的最大值)可以由 JVM 参数-XX:AutoBoxCacheMax=<size> 或系统属性-Djava.lang.Integer.IntegerCache.high=<size>来设置。

如果我们通过静态工厂 Integer.valueOf(int) 来创建 Integer 对象,首先会判断创建的对象值是否在 IntegerCache 中有缓存,有的话直接取缓存中的值,否则通过标准对象创建语法 new Interger(int) 创建并返回。

所以默认情况下,如果使用 Integer.valueOf(int) 创建的 Integer 对象值在 -128 ~ 127 之间,那么无论创建多少次,创建的每一个对象使用== 关系操作符得到的结果都是true,否则都是false

注:如果修改过java.lang.Integer.IntegerCache.high属性值,那么结果就另当别论了。

静态工厂 Integer.valueOf(int) 的设计正是对享元模式的应用。享元模式定义如下:

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

Integer.valueOf(int) 通过享元模式缓存频繁请求的值来显着提高空间和时间性能,效率远远高于通过 new Integer() 创建对象的方式。所以 Java 9 中直接弃用了new Integer(),我们以后在创建 Integer 的包装类型时,也尽量不要再使用 new Integer() 的方式了。

注:其它包装类型(Long、Short 等)也类似。

上次更新: 2 years ago