diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index 76cb54a..d813247 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -2,8 +2,11 @@ import { defineConfig } from 'vitepress'
// https://vitepress.dev/reference/site-config
export default defineConfig({
- title: "Cxx0822",
+ title: "拾光记",
description: "Cxx0822 Blog",
+ head: [
+ ['link', { rel: 'icon', href: '/blog-press/favicon.ico' }]
+ ],
base: '/blog-press/',
lang: 'zh-CN',
locales: {
@@ -13,19 +16,22 @@ export default defineConfig({
},
},
themeConfig: {
+ logo: "/logo.png",
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: 'Home', link: '/' },
- { text: 'Web', link: '/Web/' },
+ { text: 'Web后端', link: '/Web-Backend/' },
{ text: 'DevOps', link: '/DevOps/' },
- { text: 'SpringBoot', link: '/SpringBoot/' }
+ { text: 'SpringBoot', link: '/SpringBoot/' },
],
sidebar: {
- '/Web/': [
+ '/Web-Backend/': [
{
- text: 'Web',
+ text: 'Web后端',
items: [
- { text: 'MySQL知识点', link: '/Web/MySQL-Knowledge' }
+ { text: 'MySQL知识点', link: '/Web-Backend/MySQL-Knowledge' },
+ { text: 'Flyway简单使用', link: '/Web-Backend/Flyway' },
+ { text: 'MyBatis简介和使用', link: '/Web-Backend/MyBatis' }
]
},
],
@@ -44,7 +50,11 @@ export default defineConfig({
text: 'SpringBoot',
items: [
{ text: 'Spring IOC简介', link: '/SpringBoot/SpringIOC' },
- { text: 'SpringBoot启动流程', link: '/SpringBoot/SpringBoot-Start-Process' }
+ { text: 'SpringBoot启动流程', link: '/SpringBoot/SpringBoot-Start-Process' },
+ { text: 'Spring MVC简介', link: '/SpringBoot/SpringMVC' },
+ { text: 'SpringBoot Starter原理', link: '/SpringBoot/SpringBootStarter' },
+ { text: 'SpringBoot Bean简介', link: '/SpringBoot/SpringBootBean' },
+ { text: 'SpringBoot3原生镜像', link: '/SpringBoot/SpringBoot3-GraalVM' }
]
}
]
@@ -93,6 +103,9 @@ export default defineConfig({
next: '下一篇'
},
+ sidebarMenuLabel: '菜单',
+ darkModeSwitchLabel: '外观',
+
lastUpdated: {
text: '最后更新于'
}
diff --git a/docs/.vitepress/theme/components/CustomComponent.vue b/docs/.vitepress/theme/components/CustomComponent.vue
new file mode 100644
index 0000000..80563fb
--- /dev/null
+++ b/docs/.vitepress/theme/components/CustomComponent.vue
@@ -0,0 +1,27 @@
+
+
+
{{ title }}
+
{{ description }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.vitepress/theme/fonts/custom.woff2 b/docs/.vitepress/theme/fonts/custom.woff2
new file mode 100644
index 0000000..cca851d
Binary files /dev/null and b/docs/.vitepress/theme/fonts/custom.woff2 differ
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
new file mode 100644
index 0000000..3a2e46a
--- /dev/null
+++ b/docs/.vitepress/theme/index.ts
@@ -0,0 +1,12 @@
+import DefaultTheme from 'vitepress/theme'
+
+import '../theme/style.css'
+
+// 定义组件导入的类型
+interface ComponentModule {
+ default: any
+}
+
+export default {
+ extends: DefaultTheme
+}
diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css
new file mode 100644
index 0000000..019bd18
--- /dev/null
+++ b/docs/.vitepress/theme/style.css
@@ -0,0 +1,19 @@
+@font-face {
+ font-family: 'CustomFont';
+ src: url('./fonts/custom.woff2') format('woff2');
+ font-display: swap;
+}
+
+:root {
+ --vp-font-family-base: 'CustomFont', -apple-system, BlinkMacSystemFont,
+ 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
+ --vp-font-family-mono: 'CustomFont', 'Fira Code', 'Consolas', monospace;
+}
+
+:root {
+ --vp-c-brand: #10b981;
+ --vp-c-brand-light: #34d399;
+ --vp-c-brand-lighter: #6ee7b7;
+ --vp-c-brand-dark: #059669;
+ --vp-c-brand-darker: #047857;
+}
\ No newline at end of file
diff --git a/docs/DevOps/ElasticSearch.md b/docs/DevOps/ElasticSearch.md
index b52bdcc..eda7e44 100644
--- a/docs/DevOps/ElasticSearch.md
+++ b/docs/DevOps/ElasticSearch.md
@@ -50,24 +50,24 @@ volumes:
driver: local
```
- elasticsearch和kibana版本要保持一致,该镜像较大,可以先使用docker pull拉取到本地。
- ELASTIC_PASSWORD和KIBANA_PASSWORD可以通过.env配置文件设置。
- 启动时,elasticsearch可能会提示elasticsearch-data文件夹权限问题,目前解决方案为将其权限设置为777。
+ elasticsearch和kibana版本要保持一致,该镜像较大,可以先使用docker pull拉取到本地。
+ ELASTIC_PASSWORD和KIBANA_PASSWORD可以通过.env配置文件设置。
+ 启动时,elasticsearch可能会提示elasticsearch-data文件夹权限问题,目前解决方案为将其权限设置为777。
## 三、简单使用
### 3.1 安装插件
- 启动成功后,需要安装elasticsearch的分词插件analysis-ik。
+ 启动成功后,需要安装elasticsearch的分词插件analysis-ik。
进入Docker容器,输入指令:
```cmd
-bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.12.0
+bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.12.0
```
- 注意版本要匹配。https://github.com/infinilabs/analysis-ik/releases/tag/Latest
+ 注意版本要匹配。https://github.com/infinilabs/analysis-ik/releases/tag/Latest
安装完成后,重启容器。
### 3.2 更改密码
- 启动成功后,需要更改elasticsearch的账号密码(不知道为啥docker-compose文件设置的密码不行,可能是容器初始化后又重置了)。
+ 启动成功后,需要更改elasticsearch的账号密码(不知道为啥docker-compose文件设置的密码不行,可能是容器初始化后又重置了)。
进入Docker容器,输入指令:
```cmd
bin/elasticsearch-setup-passwords interactive
@@ -76,7 +76,7 @@ bin/elasticsearch-setup-passwords interactive
根据提示输入相应的账号密码。
### 3.3 新建索引
-1. 打开Elastic控制台,选择Management->Dev Tools,输入语句新建索引。
-2. 选择Management->Stack Management->Data Views,选择Create data view新建数据视图。
-3. 输入name、index pattern(刚才新建的索引)和Timestamp信息,保存数据视图。
-4. 选择Discover,选择刚才的数据视图即可查看该视图下所有数据。
+1. 打开Elastic控制台,选择Management->Dev Tools,输入语句新建索引。
+2. 选择Management->Stack Management->Data Views,选择Create data view新建数据视图。
+3. 输入name、index pattern(刚才新建的索引)和Timestamp信息,保存数据视图。
+4. 选择Discover,选择刚才的数据视图即可查看该视图下所有数据。
diff --git a/docs/DevOps/Jenkins.md b/docs/DevOps/Jenkins.md
index 6876671..a9dd0b3 100644
--- a/docs/DevOps/Jenkins.md
+++ b/docs/DevOps/Jenkins.md
@@ -85,7 +85,7 @@ Installation directory: /opt/node-v20.10.0-linux-x64
```
### 1.4.4 配置Gitee
- 选择Dashboard -> Manage Jenkins -> System,选择Gitee Configuration,输入name和URL,点击Add Credentials,选择Kind的Gitee API token,将Gitee中生成的token复制到指定位置。
+ 选择Dashboard -> Manage Jenkins -> System,选择Gitee Configuration,输入name和URL,点击Add Credentials,选择Kind的Gitee API token,将Gitee中生成的token复制到指定位置。
注:该版本新增的Gitee Token并不能在后续的项目中找到,但是又无法新增username和password形式,只能在项目的gitee配置中新增username和password的形式,不知道是什么原因?
# 二、创建工程
diff --git a/docs/DevOps/OpenObserve.md b/docs/DevOps/OpenObserve.md
index 70361cb..0f859ac 100644
--- a/docs/DevOps/OpenObserve.md
+++ b/docs/DevOps/OpenObserve.md
@@ -3,28 +3,37 @@
[Fluent Bit](https://fluentbit.io/) 是一个开源的、轻量级、高性能的日志处理器和转发器。Fluent Bit 的核心任务是:**从各种来源收集日志、指标和追踪数据,进行处理和过滤,然后将其发送到一个或多个目的地。**
#### 1.1.1 特点
-1. 极致的轻量级
- Fluent Bit 是用 C 语言编写的,运行时内存占用极低(通常只有几百 KB),CPU 使用率也非常低。这使得它成为在资源受限环境(如边缘计算、IoT 设备、容器侧车)中运行的理想选择。
-2. 高性能
- 其核心架构经过高度优化,处理数据的速度极快,能够轻松应对高吞吐量的日志流。
-3. 可插拔架构
- Fluent Bit 的功能通过“插件”来扩展。
+1. 极致的轻量级
+Fluent Bit 是用 C 语言编写的,运行时内存占用极低(通常只有几百 KB),CPU 使用率也非常低。这使得它成为在资源受限环境(如边缘计算、IoT 设备、容器侧车)中运行的理想选择。
+2. 高性能
+其核心架构经过高度优化,处理数据的速度极快,能够轻松应对高吞吐量的日志流。
+3. 可插拔架构
+Fluent Bit 的功能通过“插件”来扩展。
#### 1.1.2 插件类型
-1. Input(输入):定义数据来源,例如从文件、标准输入、TCP/UDP、系统指标(CPU/内存)、Docker 容器、Windows 事件日志等收集数据。
-2. Filter(过滤器):在数据传递过程中进行处理,例如解析(如将非结构化文本解析为 JSON)、丰富(如添加 Kubernetes 元数据)、修改(如重命名字段)、采样等。
-3. Output(输出):定义数据目的地,例如 Elasticsearch、Splunk、Kafka、Datadog、Loki、S3、另一个 Fluentd/Fluent Bit 实例等。
+1. Input(输入)
+定义数据来源,例如从文件、标准输入、TCP/UDP、系统指标(CPU/内存)、Docker 容器、Windows 事件日志等收集数据。
+2. Filter(过滤器)
+在数据传递过程中进行处理,例如解析(如将非结构化文本解析为 JSON)、丰富(如添加 Kubernetes 元数据)、修改(如重命名字段)、采样等。
+3. Output(输出)
+定义数据目的地,例如 Elasticsearch、Splunk、Kafka、Datadog、Loki、S3、另一个 Fluentd/Fluent Bit 实例等。
#### 1.1.3 核心架构与数据流
-1. Input(输入):一个或多个输入插件持续地从数据源收集数据。每条数据被读入后,会带上时间戳和标签等信息,被包装成一个内部的事件记录。
-2. Parser(解析器):(可选)输入插件可以使用解析器,将非结构化的日志数据(如 Nginx 访问日志)转换为结构化的 JSON 格式。
-3. Filter(过滤):(可选)数据会经过一个或多个过滤器插件。这些插件可以修改、丰富或删除记录。过滤器是按顺序执行的。
-4. Router(路由):根据每条记录的标签(Tag),路由器将其匹配到相应的输出插件。一个记录可以被路由到多个输出(多路复用)。
-5. Buffer(缓冲):在发送到输出之前,数据可能会在内存或文件系统中进行缓冲。
-6. Output(输出):最终,输出插件将处理好的数据发送到配置的目的地。
+1. Input(输入)
+一个或多个输入插件持续地从数据源收集数据。每条数据被读入后,会带上时间戳和标签等信息,被包装成一个内部的事件记录。
+2. Parser(解析器)
+(可选)输入插件可以使用解析器,将非结构化的日志数据(如 Nginx 访问日志)转换为结构化的 JSON 格式。
+3. Filter(过滤)
+(可选)数据会经过一个或多个过滤器插件。这些插件可以修改、丰富或删除记录。过滤器是按顺序执行的。
+4. Router(路由)
+根据每条记录的标签(Tag),路由器将其匹配到相应的输出插件。一个记录可以被路由到多个输出(多路复用)。
+5. Buffer(缓冲)
+在发送到输出之前,数据可能会在内存或文件系统中进行缓冲。
+6. Output(输出)
+最终,输出插件将处理好的数据发送到配置的目的地。
### 1.2 OpenObserve
- [OpenObserve](https://openobserve.ai/) 是一个开源的、云原生的可观测性数据平台,旨在处理日志、指标、追踪和性能数据。它的目标是成为 Elasticsearch/Logstash/Kibana (ELK)、Grafana Loki 和 Datadog 等流行解决方案的更简单、更经济高效、更高性能的替代品。
+ [OpenObserve](https://openobserve.ai/) 是一个开源的、云原生的可观测性数据平台,旨在处理日志、指标、追踪和性能数据。它的目标是成为 Elasticsearch/Logstash/Kibana (ELK)、Grafana Loki 和 Datadog 等流行解决方案的更简单、更经济高效、更高性能的替代品。
OpenObserve 是一个“一体化”的平台,你可以将所有的可观测性数据(日志、指标、追踪)都发送到它这里,然后通过统一的界面进行搜索、分析和可视化。
## 二、Docker部署
@@ -94,18 +103,18 @@ volumes:
json_date_format iso8601
```
- INPUT为日志输入源,监听24422端口。
+ INPUT为日志输入源,监听24422端口。
OUTPUT为日志输出源,将日志发送到openobserve中(这里使用的是容器名称),URI表示openobserve接收数据的api路径,default/default表示组织名称/流名称,可以更改为其他的名称。_json表示以json的格式。
## 三、简单使用
### 3.1 配置数据流
- 打开控制台,选择数据流->添加数据流,输入fluent bit配置文件中的流名称,选择数据流类型为Logs。
- 在新添加的数据流中,点击查看,跳转到日志页面即可看到上次的日志信息。
- 如果没有日志请检查FluentBit容器日志是否有错误,正确的应该会有上传成功的提示。
+ 打开控制台,选择数据流->添加数据流,输入fluent bit配置文件中的流名称,选择数据流类型为Logs。
+ 在新添加的数据流中,点击查看,跳转到日志页面即可看到上次的日志信息。
+ 如果没有日志请检查FluentBit容器日志是否有错误,正确的应该会有上传成功的提示。

### 3.2 配置邮件告警
- 首先需要配置模板和邮箱地址。
+ 首先需要配置模板和邮箱地址。
修改docker-compose.yml文件,添加邮件服务器:
```yml
openobserve:
@@ -132,9 +141,9 @@ openobserve:
- devops
```
- 这里配置587端口会有问题,使用了25端口,并且去掉了安全认证。
- 注意配置的邮件地址需要和用户名一致。
- 打开控制台,选择右上角的设置按钮,选择模板->添加模板->Email,填写标题和Body:
+ 这里配置587端口会有问题,使用了25端口,并且去掉了安全认证。
+ 注意配置的邮件地址需要和用户名一致。
+ 打开控制台,选择右上角的设置按钮,选择模板->添加模板->Email,填写标题和Body:
```json
[Alert: {alert_name}] - Severity: {alert_type}
```
@@ -162,14 +171,14 @@ openobserve:

配置完模板和地址后,选择告警->添加告警,例如可以选择当有level='critical',并且出现1次时,触发报警,并通知到指定邮箱。
-
- 周期:监控数据的时间窗口范围,即每次检查告警条件时,回溯多长时间的监控数据。如果周期 = 5分钟:每次检查时,分析最近 5 分钟的日志/指标数据。
- 频率:告警规则检查的时间间隔,即每隔多久执行一次告警条件判断。
- 通知后静默:触发告警并发送通知后,系统暂时停止重复通知的时间。
- 也可以设置为实时告警,即当告警发生时就立即触发,不会有周期和频率参数设置。
+
+ 周期:监控数据的时间窗口范围,即每次检查告警条件时,回溯多长时间的监控数据。如果周期 = 5分钟:每次检查时,分析最近 5 分钟的日志/指标数据。
+ 频率:告警规则检查的时间间隔,即每隔多久执行一次告警条件判断。
+ 通知后静默:触发告警并发送通知后,系统暂时停止重复通知的时间。
+ 也可以设置为实时告警,即当告警发生时就立即触发,不会有周期和频率参数设置。
### 3.3 配置WebHook
- 首先配置模板和WebHook地址。
+ 首先配置模板和WebHook地址。
打开控制台,选择右上角的设置按钮,选择模板->添加模板->Web Hook,填写Body:
```json
{
@@ -181,12 +190,12 @@ openobserve:
```

- 选择地址->添加地址->WebHook,选择刚才的模板,并填写URL。
- 这里可以使用企业微信的群消息推送功能,添加成功后,会提供一个WebHook地址。也可以自定义一个WebHook接收地址。
- 配置完模板和地址后,选择告警->添加告警,选择通知到刚才的WebHook地址即可。
+ 选择地址->添加地址->WebHook,选择刚才的模板,并填写URL。
+ 这里可以使用企业微信的群消息推送功能,添加成功后,会提供一个WebHook地址。也可以自定义一个WebHook接收地址。
+ 配置完模板和地址后,选择告警->添加告警,选择通知到刚才的WebHook地址即可。
### 3.4 通过API获取日志信息
- 通过http://ip:5080/swagger/index.html#/ 即可访问OpenobserveAPI接口。
+ 通过http://ip:5080/swagger/index.html#/ 即可访问OpenobserveAPI接口。
例如要获取日志,可以使用/api/{origin_id}/_search的接口:
```cmd
curl -X 'POST' \
@@ -204,11 +213,11 @@ curl -X 'POST' \
}'
```
- 注意这里要加上Basic auth认证,并提供username和password。
+ 注意这里要加上Basic auth认证,并提供username和password。

## 四、自定义日志告警服务

- 基本原理为通过提供一个HTTP的API接口,当Openobserver触发告警时,调用该接口,并传入当前的alert_name和timestamp,然后根据timestamp和Openobserver提供的API接口去查询最近一段时间内的所有日志信息,并存储到SqLite数据库中。同时也可以选择是否同步推送到企业微信和邮箱。
- 最后也需要提供一个查询历史日志告警信息的接口,并可视化显示,方便运维和开发查看。
+ 基本原理为通过提供一个HTTP的API接口,当Openobserver触发告警时,调用该接口,并传入当前的alert_name和timestamp,然后根据timestamp和Openobserver提供的API接口去查询最近一段时间内的所有日志信息,并存储到SqLite数据库中。同时也可以选择是否同步推送到企业微信和邮箱。
+ 最后也需要提供一个查询历史日志告警信息的接口,并可视化显示,方便运维和开发查看。
自定义服务参考代码:[log-alert-service](https://cxxgit.iepose.cn/Cxx0822/log-alert-service)
\ No newline at end of file
diff --git a/docs/SpringBoot/SpringBoot3-GraalVM.md b/docs/SpringBoot/SpringBoot3-GraalVM.md
new file mode 100644
index 0000000..ad3d567
--- /dev/null
+++ b/docs/SpringBoot/SpringBoot3-GraalVM.md
@@ -0,0 +1,72 @@
+# 一、原生镜像
+ 传统 Java 应用基于 JVM 运行,需要加载完整的类库和 JVM 运行时环境,导致启动时间长、内存占用高。而**原生镜像技术通过提前编译(AOT)将 Java 应用直接编译为本地机器码,无需 JVM 即可运行**,具有以下核心优势:
+
+1. 启动速度极快:毫秒级启动,相比传统 JVM 应用提升 10-100 倍、
+2. 内存占用低:仅包含应用运行所需的最小资源集合
+3. 部署体积小:通常为传统 JAR 包的 1/10 左右
+4. 适合云原生场景:尤其适合 Kubernetes 等容器化环境
+
+# 二、安装使用
+## 2.1 基础软件
+1. GraalVM(类似于JAVA JDK)下载:[官网](https://www.graalvm.org/downloads/),下载完成后需要配置环境变量
+2. native-image安装:cmd运行:gu install native-image
+3. Visual Studio Community2022 选择:使用C++的桌面开发
+
+## 2.2 结合Springboot3 项目
+1. IDEA创建Springboot3项目
+2. Project Structure选择GraalVM JDK
+3. 配置pom打包
+```xml
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+ process-aot
+
+
+
+
+
+
+
+ org.graalvm.buildtools
+ native-maven-plugin
+ 0.10.2
+
+
+
+ --enable-url-protocols=http
+
+ -H:+AddAllCharsets
+
+
+
+
+ build-native
+
+ compile-no-fork
+
+
+
+
+
+```
+4. 选择Maven->Lifecycle->clean和package,或者输入命令:mvn -Pnative native:compile
+5. 在target目录下可以看到生成的.exe文件,打开运行即可。
+
+## 三、注意事项
+ 实际体验下来发现主要存在以下几个问题
+1. 编译打包的速度非常慢
+2. 目前有些第三方库并不支持(Mybatis已支持,Mybatis Plus暂不支持)
+
+# 四、参考资料
+1. [使用 Spring Boot 和 GraalVM 构建原生镜像](https://springdoc.cn/spring-native-intro/)
+2. [GraalVM 原生镜像支持](https://docs.springframework.org.cn/spring-boot/reference/native-image/introducing-graalvm-native-images.html)
\ No newline at end of file
diff --git a/docs/SpringBoot/SpringBootBean.md b/docs/SpringBoot/SpringBootBean.md
new file mode 100644
index 0000000..5df5b27
--- /dev/null
+++ b/docs/SpringBoot/SpringBootBean.md
@@ -0,0 +1,60 @@
+## 一、Bean概念
+### 1.1 定义
+ Spring bean是Spring框架在运行时管理的对象,Bean是一个由Spring IoC容器实例化、组装和管理的对象。
+ 一个 Bean 可以是任何普通的 Java 对象,例如 POJO、Service、Respository、Controller 等等。将一个类声明为 Bean 的方式可以是在类级别上使用 `@Component` 注解或其派生注解(`@Service`、`@Repository`、`@Controller`等),也可以是通过配置文件进行显式的声明。
+
+### 1.2 实例化
+ Spring 容器负责实例化 Bean。当应用程序启动时,Spring 容器会根据配置信息或注解扫描的结果,找到并实例化所有被标记为 Bean 的类,并将它们加入容器中。实例化的过程由 Spring 的 IoC 容器负责。
+
+### 1.3 管理
+ 一旦 Bean 被实例化,Spring 容器将负责管理 Bean 的生命周期和依赖关系。它会根据配置文件或注解的信息,自动解决 Bean 之间的依赖关系,确保在需要的时候正确的注入依赖。Spring 容器还会负责销毁不再需要的 Bean。
+
+### 1.4 依赖注入
+ 依赖注入是 Spring 框架的一个重要特性,它允许通过自动或显式配置的方式将 Bean 的依赖项注入到其它 Bean 中。依赖注入可以通过构造函数注入、Setter 方法注入或字段注入的方式实现,其中最常见的是使用 `@Autowired`注解进行注入。
+
+### 1.5 作用域
+ Spring 框架提供了多种作用域(scope)来管理 Bean 的生命周期。常见的作用域包括单例(Singleton)、原型(Prototype)、会话(Session)、请求(Request)等。默认情况下,Bean 是单例的,即每个容器中只存在一个实例。但可以根据需要配置其它作用域。
+
+### 1.6 自动装配
+ Spring Boot 支持自动装配(Auto - wiring),它能够根据类型或名称自动解析和注入依赖关系。通过在需要注入的字段、构造函数或 Setter 方法上使用 `@Autowired` 注解,Spring 容器会自动查找并注入对应的 Bean。
+
+## 二、Bean生命周期
+
+
+### 2.1 实例化
+ 指创建对象的过程,也就是说,当 Spring 容器启动时,它会扫描所有的配置文件,读取 Bean 定义,然后根据定义创建 Bean 对象的实例。这个过程中,Spring 容器会使用反射机制来调用 Bean 的构造函数来实例化对象。
+
+### 2.2 属性赋值
+ 对 Bean 的实例化对象进行属性填充;
+
+### 2.3 初始化
+ 指 Bean 对象被创建后,Spring 容器会根据配置文件中的定义来对其进行一系列的属性设置、依赖注入等操作,使其可以正常运行。这个过程中,Spring 容器会调用 Bean 的一些特定方法,如 set 方法、init-method 方法等来完成对象的初始化。
+
+### 2.4 销毁
+ 执行一些预定义的销毁方法;
+
+## 三、Bean注解——@Component
+### 基本概念
+ @Component 是 Spring 框架中的一个注解,用于将类标记为 Spring 管理的组件。当一个类被 @Component 注解修饰时,Spring 会在启动时自动扫描并将该类实例化为 Bean,放入应用程序的上下文(ApplicationContext)中,以便在其他地方可以通过依赖注入使用。
+
+### 主要作用
+1. 组件扫描:Spring 通过组件扫描机制自动发现并注册被 @Component 注解的类。
+2. Bean 定义:被注解的类会被视为 Spring Bean,由 Spring 容器管理其生命周期。
+3. 依赖注入:其他组件可以通过注解(如 @Autowired)注入这些 Bean。
+
+### 其他衍生注解
+| **注解** | **所属层** | **继承关系** | **适用场景** |
+|------------------|--------------------|-------------------|----------------------------------------------------------------------------|
+| **@Component** | 通用组件 | 基础注解 | 不适合特定层的组件(如工具类、配置类) |
+| **@Repository** | 数据访问层 (DAO) | 继承 @Component | 数据库操作类、ORM 映射类(如 JPA Repository) |
+| **@Service** | 服务层 (Service) | 继承 @Component | 业务逻辑处理(如订单处理、用户认证) |
+| **@Controller** | 控制层 (MVC/Web) | 继承 @Component | 处理 HTTP 请求的控制器(如 REST API、Web 页面控制器) |
+| **@RestController** | 控制层 (REST API) | 继承 @Controller | RESTful API 接口开发 |
+
+| **注解** | **功能描述** | **Spring 自动处理特性** |
+|------------------|-----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
+| **@Component** | 标记类为 Spring Bean,通过组件扫描自动注册。
无特定语义,是其他组件注解的基础。 | - Bean 生命周期管理
- 依赖注入支持 |
+| **@Repository** | 标记数据访问组件(如数据库操作类),
自动处理数据访问异常。 | - 异常转换
- DAO 组件扫描 |
+| **@Service** | 标记业务逻辑组件,负责处理业务流程、事务管理等。
提供语义化,明确该类在架构中的角色。 | - 与 @Transactional 注解默认集成
- IDE 识别为服务层组件 |
+| **@Controller** | 标记 Web 控制器,处理 HTTP 请求。
与 Spring MVC 框架紧密集成。 | - 请求映射自动注册
- 支持 @RequestMapping、@GetMapping 等注解
- 视图解析(返回视图名称或 JSON) |
+| **@RestController** | @Controller + @ResponseBody 的组合,专门用于 RESTful API,直接返回 JSON/XML 等数据。 | - 所有方法默认返回 JSON/XML(无需每个方法添加 @ResponseBody) |
\ No newline at end of file
diff --git a/docs/SpringBoot/SpringBootStarter.md b/docs/SpringBoot/SpringBootStarter.md
new file mode 100644
index 0000000..7b900bb
--- /dev/null
+++ b/docs/SpringBoot/SpringBootStarter.md
@@ -0,0 +1,105 @@
+# 一、简介
+ Spring Boot Starter是一组预定义的依赖项集合,旨在简化Maven或Gradle等构建工具中的依赖管理。每个Starter都包含了实现特定功能所需的库和组件,以及相应的配置文件。开发者只需在项目中引入相应的Starter依赖,即可快速搭建起具备该功能的项目骨架。
+ Starter=依赖+自动配置+配置文件
+
+# 二、实现原理
+## 2.1 传统实现
+ 例如引入Spring中的jpa,则需要以下步骤:
+1. 在Maven中引入数据库依赖
+2. 在Maven中引入jpa依赖
+3. 在配置文件中配置属性
+4. 调试程序
+
+ 每次新建项目都需要重复此流程,操作繁琐。
+
+## 2.2 自定义Starter实现
+1. 新建Maven项目,在pom.xml文件中定义需要的依赖项。
+2. 创建自动配置类 AutoConfigurationTest,添加@configuration注解,使其能够被SpringBoot自动扫描到。
+3. 添加自动装配机制,在src/main/resources/META-INF文件夹下创建spring.factories文件,添加以下配置:
+
+```bash
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.example.springbootstartercustom.AutoConfigurationTest
+```
+
+ 注:这里文件夹和文件名一定要正确,因此SpringFactoriesLoader中就是这么定义的。
+
+4. 在配置文件中自定义属性(可选)。
+5. 安装打包到maven仓库中。
+6. 其他项目通过pom.xml文件引入该starter。
+
+## 2.3 Starter实现原理
+ 加载依赖->扫描自动配置类->加载配置文件
+
+# 三、高级特性
+## 3.1 可插拔Starter
+ 所谓可插拔就是可以自行决定是否需要加载该starter的功能。例如可以通过注解的方式决定是否加载。
+
+1. 定义注解
+
+```java
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnableAutoConfigTest {
+
+}
+```
+
+2. 在自动配置类 AutoConfiguration中增加条件注解
+
+```java
+@Configuration
+@ConditionalOnBean(annotation = EnableAutoConfigTest.class)
+public class AutoConfigurationTest {
+}
+```
+
+3. 在相应位置添加@EnableAutoConfigTest注解该stater才会生效。
+
+## 3.2 自定义配置文件
+ 所谓自定义配置文件,就是可以在引入stater后,可以通过修改配置文件覆盖原来的配置属性,从而灵活配置stater功能。
+
+1. 引用spring-boot-configuration-processor
+
+```xml
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+```
+
+2. 定义Properties配置类
+
+```java
+@ConfigurationProperties(prefix = "test")
+public class TestProperties {
+ private String name = "test";
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+```
+
+3. 在自动配置类 AutoConfigurationTest中引用
+
+```java
+@Configuration(proxyBeanMethods = false)
+@Import({TestProperties.class})
+public class AutoConfigurationTest {
+ @Resource
+ private TestProperties testProperties;
+}
+```
+
+4. 在引入的stater工程中,修改配置文件:
+
+```yaml
+test:
+ name: test1
+```
\ No newline at end of file
diff --git a/docs/SpringBoot/SpringMVC.md b/docs/SpringBoot/SpringMVC.md
new file mode 100644
index 0000000..2abcf5b
--- /dev/null
+++ b/docs/SpringBoot/SpringMVC.md
@@ -0,0 +1,89 @@
+# 一、基础概念
+ Spring MVC(Spring Model-View-Controller)是 Spring Framework 中的一部分,它是一个基于 **请求驱动** 的 Web 框架,主要用于构建 Web 应用程序,并且遵循 MVC(模型-视图-控制器) 设计模式。它将 Web 应用的业务逻辑、用户界面和请求处理分离,使得代码更加模块化和可维护。
+
+# 二、具体流程
+
+
+1. **客户端发起HTTP请求**
+
+ 客户端(浏览器、API 客户端等)向服务器发送 HTTP 请求。请求包含了目标 URL、HTTP 方法(GET、POST 等)以及可能的请求参数。
+前端通过发送 HTTP 请求(通常是 AJAX 请求)到后端的 API 端点,并期望获得响应(通常是 JSON 数据)。
+
+2. **请求到达 DispatcherServlet**
+
+ 所有 HTTP 请求都会先到达 Spring MVC 的核心组件:**DispatcherServlet**。它是前端控制器,负责将请求分发给正确的处理器。DispatcherServlet 是所有请求的入口,Spring Boot 会自动配置它。
+ DispatcherServlet 接受所有的 HTTP 请求,根据请求 URL 和 HTTP 方法,定位匹配的控制器方法,将请求交给相应的 Handler Mapping 来匹配控制器。在请求处理前后,执行 拦截器(可选)。最终通过 View Resolver 返回一个合适的视图(对于 RESTful API,通常返回 JSON 格式的数据)。
+
+3. **查找处理器(Handler Mapping)**
+
+ DispatcherServlet 根据请求的 URL 和 HTTP 方法,查找与之匹配的处理器方法(通常是一个控制器中的方法)。这是由 HandlerMapping 完成的。Spring MVC 提供了多种方式来映射 URL 到控制器方法,例如 @RequestMapping、@GetMapping 等注解。
+ @RestController:该注解标记的类会返回 JSON 数据。
+ @RequestMapping:用于映射 URL 路径和 HTTP 方法。
+ @GetMapping、@PostMapping 等:简化版本的 @RequestMapping。
+
+4. **执行拦截器(Interceptor)**
+
+ 在请求到达控制器之前,DispatcherServlet 会依次执行配置的拦截器。拦截器主要用于日志记录、安全检查、请求参数的预处理等。
+ preHandle:请求进入控制器方法之前。
+ postHandle:请求完成后,视图渲染之前。
+ afterCompletion:视图渲染完成后。
+ **如果拦截器的 preHandle 方法返回 false,请求会被拦截,后续的处理不会继续进行。**
+
+5. **控制器方法处理请求(Handler Execution)**
+
+ DispatcherServlet 调用合适的控制器方法来处理请求。控制器方法负责处理请求的业务逻辑,并返回一个 Java 对象,这个对象会被自动转换成 JSON 格式返回给客户端。
+ Spring 通过 @ResponseBody 注解(或 @RestController)实现将 Java 对象自动转换为 JSON 格式。默认情况下,Spring 使用 Jackson 来将 Java 对象序列化成 JSON 数据。
+ @RestController:将控制器标记为返回 JSON 数据的 RESTful 控制器。
+ @ResponseBody:标记方法返回的数据需要直接作为响应体返回,而不是解析为视图。
+ @RequestParam:用于获取单个请求参数。
+ @PathVariable:用于从 URL 中提取变量(如 /users/{id} 中的 {id})。
+
+6. **响应返回客户端**
+
+ DispatcherServlet 将处理完的结果(JSON 数据)返回给客户端。响应数据通常会包含:
+ **状态码**:如 200 OK(成功)、201 Created(资源创建成功)、404 Not Found(资源未找到)、500 Internal Server Error(服务器错误)等。
+ **响应头**:通常包括 Content-Type: application/json,表示响应体是 JSON 格式。
+ **响应体**:包含返回的数据,通常是一个 JSON 格式的对象或数组。
+
+注:以上只适用于基于RESTful API 前后端分离的架构。
+
+# 三、完整流程
+
+ 在SpringMVC前面还有Tomcat容器层。客户端发起请求后,先经过Tomcat容器,根据请求的 URL 确定该请求是否是静态资源请求(如 .html、.css、.js)。如果是静态资源请求,Tomcat 会直接返回文件,而不经过 Spring MVC 的请求处理链。对于动态请求(如请求 /user 等),Tomcat 会将这些请求交给 DispatcherServlet 进行处理。
+ 在进入DispatcherServlet前可以增加过滤器进行处理。过滤器不属于Spring部分。
+ Tomcat 是一个轻量级的 Web 服务器和 Servlet 容器,支持 Java Servlet 和 JSP 规范,能够处理 HTTP 请求并生成动态 Web 内容。
+ Servlet 是 Java 编写的服务器端程序,能够接收 HTTP 请求并生成响应,它是动态 Web 内容生成的核心技术。
+ Tomcat 管理 Servlet 的生命周期,并负责处理客户端的请求和返回响应。
+
+# 四、重要知识点
+## 4.1 拦截器和过滤器区别
+1. 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
+2. 拦截器只能对action请求(DispatcherServlet 映射的请求)起作用,而过滤器则可以对几乎所有的请求起作用。
+3. 拦截器可以访问容器中的Bean(DI),而过滤器不能访问(基于spring注册的过滤器也可以访问容器中的bean)。
+4. 执行顺序:过滤器->拦截器
+
+## 4.2 拦截器执行顺序
+ HandlerInterceptor 拦截器执行顺序:
+1. preHandle():请求处理前 按注册顺序依次执行。
+2. Controller:请求处理 请求到达Controller并被处理。
+3. postHandle():请求处理后,视图渲染前 按注册顺序逆序执行。
+4. afterCompletion():视图渲染后 按注册顺序逆序执行。
+
+## 4.3 请求和响应体拦截器
+ RequestBodyAdvice, ResponseBodyAdvice主要发生在Controller执行前后:
+1. preHandle():请求处理前
+2. beforeBodyRead:请求体反序列化前
+3. @RequestBody:Controller方法参数绑定
+4. Controller:请求处理
+5. beforeBodyWrite():响应体序列化之前
+6. postHandle():请求处理后
+7. 视图渲染
+8. afterCompletion():请求结束
+
+## 4.4 @Controller 和 @RestController区别
+ @Controller:用于定义一个 Spring MVC 控制器类。它通常用于返回视图(如 JSP 或 Thymeleaf)。
+ @RestController:是 @Controller 和 @ResponseBody 的组合,用于开发 RESTful API。它将方法的返回值直接写入 HTTP 响应体中,通常返回 JSON 或 XML 格式的数据。
+
+## 4.5 异常处理
+ @ExceptionHandler:用于控制器类或方法中处理特定异常。它会捕获指定的异常并返回相应的响应(如错误页面、错误消息等)。
+ @ControllerAdvice:是一个全局异常处理器,用于捕获应用中所有控制器抛出的异常。
diff --git a/docs/SpringBoot/index.md b/docs/SpringBoot/index.md
index 92191eb..b80933d 100644
--- a/docs/SpringBoot/index.md
+++ b/docs/SpringBoot/index.md
@@ -7,3 +7,7 @@ title: SpringBoot
- [Spring IOC简介](/SpringBoot/SpringIOC)
- [SpringBoot启动流程](/SpringBoot/SpringBoot-Start-Process)
+- [Spring MVC简介](/SpringBoot/SpringMVC)
+- [SpringBoot Starter原理](/SpringBoot/SpringBootStarter)
+- [SpringBoot Bean简介](/SpringBoot/SpringBootBean)
+- [SpringBoot3原生镜像](/SpringBoot/SpringBoot3-GraalVM)
\ No newline at end of file
diff --git a/docs/Web-Backend/Flyway.md b/docs/Web-Backend/Flyway.md
new file mode 100644
index 0000000..eb67298
--- /dev/null
+++ b/docs/Web-Backend/Flyway.md
@@ -0,0 +1,57 @@
+# 一、简介
+ Flyway 是一个开源的数据库版本控制工具,它极大地简化了数据库的迁移和版本管理。它的核心思想是像**用 Git 管理代码一样来管理数据库的结构**。
+
+# 二、原理
+ Flyway 通过在数据库中创建一个名为 flyway_schema_history的特殊表来工作
+| 列名 | 含义 |
+| - | - |
+| installed_rank | 执行顺序 |
+| version | 脚本的版本号 |
+| description | 脚本的描述 |
+| type | 脚本类型(通常是 SQL) |
+| script | 脚本文件名 |
+| checksum | 脚本文件的校验和(用于检测篡改) |
+| installed_by | 执行人 |
+| installed_on | 执行时间 |
+| execution_time | 执行耗时(毫秒) |
+| success | 是否成功 |
+
+ 工作流程:
+1. 应用启动时,Flyway 会检查配置的数据库路径。
+2. 检查目标数据库中的 flyway_schema_history表。
+3. 将数据库路径下的迁移脚本与 flyway_schema_history表中的记录进行对比。
+4. 按照版本号顺序执行那些尚未执行的迁移脚本。
+5. 执行成功后,将记录插入 flyway_schema_history表。
+
+## 2.1 校验和计算
+ Flyway 使用 CRC32 算法 计算 SQL 脚本文件的校验和(Checksum)。Javs使用32位有符号整数存储,因此有时会得到负数。可以通过`mvn flyway:info`查看每个脚本的校验和。
+
+# 三、与SpringBoot集成
+## 3.1 添加依赖
+```xml
+
+ org.flywaydb
+ flyway-core
+
+```
+
+## 3.2 配置数据源
+```yml
+spring:
+ flyway:
+ enabled: true
+ locations: classpath:db/migration
+ baseline-on-migrate: true # 如果数据库非空,且无 flyway_schema_history 表,则先创建基线版本
+```
+ `baseline-on-migrate: true`,当数据库已经存在数据,但是没有flyway_schema_history表时,Flyway会插入一条基线数据,并标记为1.0版本,则后续的迁移脚本只会执行比1.0版本更高的数据库文件。
+ **如果设置为false,如果数据库已经存在数据时,Flyway会报错。**
+ 因此需要避免这种情况的存在,在**初始发布应用时,要保证数据库为空**。
+
+## 3.3 创建数据库脚本
+ 在项目的资源目录 src/main/resources下创建文件夹 db/migration。
+ Flyway 的 SQL 脚本文件名有严格的命名规则:`V__.sql`
+ 例如V1.0.0_001__20251027.sql,表示v1.0.0版本的第一个sql,日期为2025年10月27日。
+ **创建了迁移脚本,一旦应用,就不可修改,否则会导致校验错误。如果确实要修改,请再创建一个脚本。**
+
+## 3.4 启动程序
+ 启动程序后。Flyway会自动在数据库中创建flyway_schema_history表,然后扫描db/migration目录下的所有脚本,按顺序执行sql文件,并记录到flyway_schema_history表中。
diff --git a/docs/Web-Backend/MyBatis.md b/docs/Web-Backend/MyBatis.md
new file mode 100644
index 0000000..8bc7c05
--- /dev/null
+++ b/docs/Web-Backend/MyBatis.md
@@ -0,0 +1,453 @@
+# 一、简介
+ [MyBatis](https://mybatis.org/mybatis-3/)是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
+
+# 二、安装
+### 2.1 引入依赖
+ 在`pom.xml`文件中,引入依赖:
+
+```xml
+
+ org.mybatis
+ mybatis
+ x.x.x
+
+```
+
+ 可以在Github中查看[MyBatis](https://github.com/mybatis/mybatis-3)最新版本号。
+
+### 2.2 配置文件
+ 在`resource`文件夹中新建mybatis-config.xml文件和mapper->BlogMapper.xml映射文件:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+ 注:如果使用MySql数据库,需要增加MySql驱动依赖:
+
+```xml
+
+ mysql
+ mysql-connector-java
+ 8.0.12
+
+```
+
+### 2.3 定义映射语句
+ 新建dao->BlogDao.java:
+
+```java
+public interface BlogDao {
+ Blog selectBlog(@Param("id") Integer id);
+}
+```
+
+ BlogMapper.xml:
+
+```xml
+
+
+
+
+
+```
+
+### 2.4 执行SqlSession
+```java
+// 配置文件路径
+String resource = "mybatis-config.xml";
+try {
+ // 读取配置文件
+ InputStream inputStream = Resources.getResourceAsStream(resource);
+ // 构建SqlSession工厂
+ SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
+ // 获取SqlSession
+ SqlSession session = sqlSessionFactory.openSession();
+ // 获取映射文件
+ BlogDao blogDao = session.getMapper(BlogDao.class);
+ // 执行已映射的SQL语句
+ Blog blog = blogDao.selectBlog(101);
+ System.out.println(blog);
+ // 关闭SqlSession
+ session.close();
+} catch (IOException e) {
+ throw new RuntimeException(e);
+}
+```
+
+ 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。
+ SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
+ 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
+
+### 2.5 作用域和生命周期
+1. SqlSessionFactoryBuilder
+
+ 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
+
+2. SqlSessionFactory
+
+ SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
+
+3. SqlSession
+
+ 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
+
+# 三、注入SpringBoot框架
+## 3.1 引入依赖
+ 将之前MyBatis的依赖替换成MyBatis的SpringBoot Starter:
+
+```xml
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 2.3.0
+
+```
+
+## 3.2 配置文件
+ 在Resource文件夹下新建application.yml:
+
+```yaml
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/mybatis_learn?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
+ username: root
+ password: 123456
+
+mybatis:
+ # mapper文件路径
+ mapper-locations: classpath*:mapper/*Mapper.xml
+ configuration:
+ # 开启日志
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+```
+
+ 注:这里的url的写法和XML文件中的写法不一致。
+
+# 3.3 定义映射语句
+ 在原映射接口文件BlogDao.java中添加@Mapper注解
+
+## 3.4 实现原理
+ 引入mybatis-spring-boot-starter模块之后,其可以:
+
+1. **自动检测DataSource**
+2. **使用SqlSessionFactoryBean注册SqlSessionFactory 实例,并设置DataSource数据源**
+3. **基于SqlSessionFactory自动注册SqlSessionTemplate实例**
+4. **自动扫描@Mapper注解类,并通过SqlSessionTemplate注册到Spring Context中**
+
+ 每次执行@Mapper映射文件中的接口时,都会自动开启一个SqlSession并在执行结束时关闭。
+
+## 3.5 执行映射语句
+```java
+Blog blog = blogDao.selectBlog(101);
+System.out.println(blog);
+```
+
+ 相较之前的写法,节省了大量的配置工作。
+
+# 四、高级特性
+## 4.1 动态参数
+```xml
+#{}是参数占位符的标记,它可以防止SQL注入,当使用#{}时,MyBatis会自动处理参数的数据类型,
+如果参数是字符串,它会给传入的值加上引号,这样可以有效地防止SQL注入攻击。
+
+${}则是直接将参数值嵌入SQL语句中。当使用${}时,传入的参数会直接显示在SQL中,
+MyBatis不会对参数进行任何类型转换或加引号处理。一般用在动态表名、列名或数据库名称中。
+```
+
+## 4.2 SQL片段
+ 可以用来定义可重复的SQL代码片段:
+
+```xml
+
+ id, username, email, phone
+
+
+
+```
+
+## 4.3 批量操作
+ 推荐使用集合方式批量操作:
+
+```java
+@Mapper
+public interface UserMapper {
+ Integer insertUsers(@Param("list") List userList);
+}
+
+```
+
+```xml
+
+ INSERT INTO user (username, password)
+ VALUES
+
+ (#{item.username}, #{item.password})
+
+
+```
+
+## 4.4 结果映射
+ 复杂结果缓存
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+ 其中``也可以使用嵌套查询:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+ 如果需要传递参数,可以在``添加`column`属性:
+
+```xml
+
+
+
+
+```
+
+ 注:建立在非列表数据时使用嵌套查询,否则每查到一个数据都会进行一次子查询操作。
+
+## 4.5 一二级缓存
+ 默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
+
++ 映射语句文件中的所有 select 语句的结果将会被缓存。
++ 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
++ 一级缓存和二级缓存区别在于一级缓存只针对一次SqlSession,二级缓存针对全局范围。
+
+## 4.6 动态SQL
++ if :是/否
+
+```xml
+
+```
+
++ choose、when、otherwise:选择其中一个
+
+```xml
+
+```
+
++ where、set:解决SQL语法问题
+
+```xml
+
+
+
+ update Author
+
+ username=#{username},
+ password=#{password},
+
+ where id=#{id}
+
+```
+
+ where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
+
+# 五、自定义类型处理器
+ MyBatis 在预处理语句(PreparedStatement)中设置参数时,会从 Java 类型(javaType)转换为 JDBC 类型(jdbcType);而从结果集中取出值时,会将 JDBC 类型转换为 Java 类型。这个转换工作就是由 TypeHandler来完成的。
+ 需要创建一个类来实现 org.apache.ibatis.type.TypeHandler接口,或者继承 org.apache.ibatis.type.BaseTypeHandler类实现自定义类型处理器。
+ 需要实现的方法:
+```java
+/**
+ * 将Java对象设置到PreparedStatement中(Java类型 → JDBC类型)
+ * @param ps PreparedStatement对象
+ * @param i 参数位置(从1开始)
+ * @param parameter 要设置的Java对象(非空)
+ * @param jdbcType JDBC类型
+ */
+@Override
+public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
+ // 实现转换逻辑:T → JDBC类型
+}
+
+/**
+ * 根据列名从ResultSet中获取值(JDBC类型 → Java类型)
+ * @param rs ResultSet对象
+ * @param columnName 列名
+ * @return 转换后的Java对象
+ */
+@Override
+public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
+ // 实现转换逻辑:JDBC类型 → T
+}
+
+/**
+ * 根据列索引从ResultSet中获取值
+ * @param rs ResultSet对象
+ * @param columnIndex 列索引(从1开始)
+ * @return 转换后的Java对象
+ */
+@Override
+public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+ // 实现转换逻辑:JDBC类型 → T
+}
+
+/**
+ * 从CallableStatement中获取值(用于存储过程)
+ * @param cs CallableStatement对象
+ * @param columnIndex 列索引
+ * @return 转换后的Java对象
+ */
+@Override
+public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+ // 实现转换逻辑:JDBC类型 → T
+}
+```
+
+ 例如自定义一个处理 MEDIUMBLOB 字段与 Base64 字符串的转换:
+```java
+/**
+ * 处理 MEDIUMBLOB 字段与 Base64 字符串的转换
+ */
+@MappedJdbcTypes(JdbcType.BLOB)
+@MappedTypes(String.class)
+public class BlobToBase64TypeHandler extends BaseTypeHandler {
+
+ @Override
+ public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
+ // Base64字符串 -> 数据库的byte[]
+ if (parameter != null && !parameter.trim().isEmpty()) {
+ byte[] bytes = Base64.getDecoder().decode(parameter);
+ ps.setBytes(i, bytes);
+ } else {
+ ps.setBytes(i, null);
+ }
+ }
+
+ @Override
+ public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
+ // 数据库的byte[] -> Base64字符串
+ byte[] bytes = rs.getBytes(columnName);
+ return bytes != null ? Base64.getEncoder().encodeToString(bytes) : null;
+ }
+
+ @Override
+ public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+ byte[] bytes = rs.getBytes(columnIndex);
+ return bytes != null ? Base64.getEncoder().encodeToString(bytes) : null;
+ }
+
+ @Override
+ public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+ byte[] bytes = cs.getBytes(columnIndex);
+ return bytes != null ? Base64.getEncoder().encodeToString(bytes) : null;
+ }
+}
+```
diff --git a/docs/Web/MySQL-Knowledge.md b/docs/Web-Backend/MySQL-Knowledge.md
similarity index 92%
rename from docs/Web/MySQL-Knowledge.md
rename to docs/Web-Backend/MySQL-Knowledge.md
index b73fe2c..2881f0d 100644
--- a/docs/Web/MySQL-Knowledge.md
+++ b/docs/Web-Backend/MySQL-Knowledge.md
@@ -2,39 +2,39 @@
## 一、基础知识
### 1.1 数据类型
#### 1.1.1 汇总
-|类型|存储空间|范围|适用场景|备注|
-| :-------------------------------------------------------------------------------------------------: | :-----------------: | :--------------------------: | :-----------------------: | :------------------------------------: |
-|TINYINT|1字节|-128 \~ 127|状态码、年龄、布尔值||
+|类型|存储空间|范围|适用场景|
+| :-------------------------------------------------------------------------------------------------: | :-----------------: | :--------------------------: | :-----------------------: |
+|TINYINT|1字节|-128 \~ 127|状态码、年龄、布尔值|
|SMALLINT|2字节|-32,768 \~ 32,767|小范围计数、年份||
-|MEDIUMINT|3字节|-8,388,608 \~ 8,388,607|中型ID、访问量统计||
-|INT/INTEGER|4字节|-2\^31 \~ 2\^31-1|用户ID、订单号(常用)||
-|BIGINT|8字节|-2\^63 \~ 2\^63-1|分布式ID、大数据量计数||
+|MEDIUMINT|3字节|-8,388,608 \~ 8,388,607|中型ID、访问量统计|
+|INT/INTEGER|4字节|-2\^31 \~ 2\^31-1|用户ID、订单号(常用)|
+|BIGINT|8字节|-2\^63 \~ 2\^63-1|分布式ID、大数据量计数|
|DECIMAL(M,D)|变长(M+2字节)||金融金额、精确计算|精确小数,M\=总位数,D\=小数位|
-|FLOAT|4字节||科学测量、非精确计算|单精度浮点,约6-7位有效数字|
-|DOUBLE|8字节||地理坐标、高精度计算|双精度浮点,约15位有效数字|
-|CHAR(M)|255字符||固定长度编码、MD5哈希||
-|VARCHAR(M)|65,535字节||用户名、地址等变长数据||
-|TINYTEXT|255字节||短标题、简介||
-|TEXT|65,535字节||文章内容、评论||
-|MEDIUMTEXT|16MB (2\^24-1)||博客文章、产品描述||
-|LONGTEXT|4GB (2\^32-1)||电子书、大型文档||
-|DATE|||纯日期||
-|TIME(fsp)|||可指定微秒精度(0-6)||
-|DATETIME(fsp)|||高精度时间记录||
-|TIMESTAMP(fsp)|||自动时区转换,4字节存储||
+|FLOAT|4字节||科学测量、非精确计算|
+|DOUBLE|8字节||地理坐标、高精度计算|
+|CHAR(M)|255字符||固定长度编码、MD5哈希|
+|VARCHAR(M)|65,535字节||用户名、地址等变长数据|
+|TINYTEXT|255字节||短标题、简介|
+|TEXT|65,535字节||文章内容、评论|
+|MEDIUMTEXT|16MB (2\^24-1)||博客文章、产品描述|
+|LONGTEXT|4GB (2\^32-1)||电子书、大型文档|
+|DATE|||纯日期|
+|TIME(fsp)|||可指定微秒精度(0-6)|
+|DATETIME(fsp)|||高精度时间记录|
+|TIMESTAMP(fsp)|||自动时区转换,4字节存储|
|ENUM|||性别、状态等有限选项|`gender ENUM('M','F','O')`|
|SET|||用户兴趣、文章标签|`tags SET('red','green','blue')`|
-|TINYBLOB|255字节||微小二进制对象||
-|BLOB|65KB||标准二进制对象||
-|MEDIUMBLOB|16MB||中等二进制对象||
-|LONGBLOB|4GB||超大二进制对象||
+|TINYBLOB|255字节||微小二进制对象|
+|BLOB|65KB||标准二进制对象|
+|MEDIUMBLOB|16MB||中等二进制对象|
+|LONGBLOB|4GB||超大二进制对象|
#### 1.1.2 法则
- 整数选择:优先INT,大数量用BIGINT,布尔值用TINYINT(1)或BIT(1)
- 小数选择:金融金额必须用DECIMAL,非精确测量可用FLOAT/DOUBLE
- 字符串选择:定长编码用CHAR,变长文本用VARCHAR,大文本用TEXT系列
- 时间选择:日期用DATE,精确时间用DATETIME,自动更新用TIMESTAMP
- 特殊场景:多选项用SET,结构化数据用JSON
+ **整数选择**:优先INT,大数量用BIGINT,布尔值用TINYINT(1)或BIT(1)
+ **小数选择**:金融金额必须用DECIMAL,非精确测量可用FLOAT/DOUBLE
+ **字符串选择**:定长编码用CHAR,变长文本用VARCHAR,大文本用TEXT系列
+ **时间选择**:日期用DATE,精确时间用DATETIME,自动更新用TIMESTAMP
+ **特殊场景**:多选项用SET,结构化数据用JSON
### 1.2 常用函数
#### 1.2.1 字符串函数
@@ -105,7 +105,7 @@ FROM employees;
```
## 二、索引
- 索引是对数据库表中的一列或多列值进行**排序**的一种结构,使用索引可以快速访问数据库表中的特定信息。
+ 索引是对数据库表中的一列或多列值进行**排序**的一种结构,使用索引可以快速访问数据库表中的特定信息。
**索引相当于图书上的目录,可以根据目录上的页码快速找到所需的内容,提高性能(查询速度)**
### 2.1 优缺点
@@ -133,7 +133,7 @@ FROM employees;
### 2.3 数据结构
在 MySQL 中,MyISAM 引擎和 InnoDB 引擎都是使用 B+Tree 作为索引结构。

- 例如要查找id=75的用户:`SELECT * FROM users WHERE id = 75`
+ 例如要查找id=75的用户:`SELECT * FROM users WHERE id = 75`
查找步骤:
1. 从根节点开始,75在50~100之间,走中间分支
2. 到达叶子节点,找到id=75的数据位置
@@ -148,8 +148,8 @@ FROM employees;
|只在叶子存数据|内部节点小|更多索引数据放入内存|
### 2.4 索引类型
-1. 主键索引
- 主键索引是最特殊的索引。
+1. 主键索引
+主键索引是最特殊的索引。
```sql
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
@@ -173,18 +173,18 @@ CREATE INDEX idx_name ON users(name);
SELECT * FROM users WHERE name = "张三";
```
-4. 复合索引
- 多个字段组合的索引
+4. 复合索引
+多个字段组合的索引
```sql
CREATE INDEX idx_name_age_city ON users(name, age, city);
SELECT * FROM users WHERE name = '张三';
SELECT * FROM users WHERE name = '张三' AND age = 25;
SELECT * FROM users WHERE name = '张三' AND age = 25 AND city = '北京';
-SELECT * FROM users WHERE age = 25; -- 无法使用索引
-SELECT * FROM users WHERE city = '北京'; -- 无法使用索引
+SELECT * FROM users WHERE age = 25; -- 无法使用索引
+SELECT * FROM users WHERE city = '北京'; -- 无法使用索引
```
- 复合索引的使用最左前缀原则。
+ 复合索引的使用最左前缀原则。
`CREATE INDEX idx_name_age_city ON users(name, age, city);`相当于创建了3个索引:`users(name),users(name, age),users(name, age, city)`。
### 2.5 索引设计
@@ -317,7 +317,6 @@ COMMIT;
* 并发性: **中等**。比 `READ COMMITTED` 稍低,因为锁(特别是 Next-Key Locks)可能持有更长时间,覆盖更大的范围(索引区间)。
* 数据一致性: **好**。保证了事务内读取数据的稳定性(同一行可重复读),并通过机制有效防止了幻读,满足大多数应用的需求。
* **使用场景:** MySQL 的默认选择,适用于绝大多数需要保证事务内数据读取一致性的场景,如订单处理、账户管理等。是兼顾一致性和并发性的良好平衡点。
- *
4. 串行化 (SERIALIZABLE)
* 特点: 最高的隔离级别。它通过强制事务**串行执行**来实现,所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。
* 允许的问题:
@@ -357,7 +356,7 @@ COMMIT;
### 4.2 重做日志(Redo Log)
#### 4.2.1 概念
- 重做日志是 InnoDB 存储引擎特有的日志,它记录的是 “物理级别” 上的页修改信息,主要用于 崩溃恢复(Crash Recovery)。
+ 重做日志是 InnoDB 存储引擎特有的日志,它记录的是 “物理级别” 上的页修改信息,主要用于 崩溃恢复(Crash Recovery)。
InnoDB 使用 WAL(Write-Ahead Logging,预写日志)技术,即 事务提交时,先写 redo log,再写磁盘数据页,从而保证即使系统崩溃,也能通过 redo log 恢复数据。
#### 4.2.2 作用
@@ -375,13 +374,13 @@ COMMIT;
### 4.4 和事务、锁之间的关系
例如,当执行一条SQL语句时,事务、锁、日志等之间的关系:
1. 发起一个事务
-2. 执行一系列的DML操作(如 INSERT/UPDATE/DELETE)
- **涉及 锁:对操作的数据行或表加锁,防止其他事务干扰。**
- **涉及 隔离级别:决定其他事务是否能“看到”你未提交的数据。**
+2. 执行一系列的DML操作(如 INSERT/UPDATE/DELETE)
+ **涉及 锁:对操作的数据行或表加锁,防止其他事务干扰。**
+ **涉及 隔离级别:决定其他事务是否能“看到”你未提交的数据。**
**涉及 undo log:如果事务回滚,可以根据 undo log 恢复旧值。**
-3. 事务提交(commit) 或 回滚(rollback)
- **redo log:保证即使宕机,已提交事务的修改也不丢失(持久性)。**
- **binlog:记录数据变更,用于主从复制与时间点恢复。**
+3. 事务提交(commit) 或 回滚(rollback)
+ **redo log:保证即使宕机,已提交事务的修改也不丢失(持久性)。**
+ **binlog:记录数据变更,用于主从复制与时间点恢复。**
**undo log:用于实现事务回滚、MVCC。**
4. **背后有日志系统默默记录一切,锁系统保障并发安全,隔离级别定义了“你能看到啥”。**
@@ -393,7 +392,6 @@ COMMIT;
5. 锁保障并发安全,日志保障操作可恢复。两者从不同维度确保数据库的正确性。锁:是在运行时控制谁可以访问哪些数据,是 并发控制 的手段。日志:是在磁盘上记录操作过程,是 故障恢复 & 事务一致性 的手段。
6. 隔离级别定义了事务间数据的可见性,而日志(尤其是 undo log 和 binlog)为这种“可见性”提供了实现基础。undo log 是实现 MVCC(多版本并发控制) 的基础,而 MVCC 是 REPEATABLE READ 等隔离级别的关键。binlog 虽不直接影响隔离性,但它记录了事务的变更历史,是构建主从环境、实现数据恢复的基础。
-
## 五、优化
### 5.1 Explain 执行计划
`EXPLAIN`是 MySQL 自带的一个诊断工具,它可以模拟 MySQL 查询优化器的执行过程,对`SELECT`语句(在 MySQL 8.0 及以上版本,也支持对`UPDATE`、`DELETE`等语句使用)进行分析,并输出该语句的执行计划。
diff --git a/docs/Web-Backend/index.md b/docs/Web-Backend/index.md
new file mode 100644
index 0000000..7572603
--- /dev/null
+++ b/docs/Web-Backend/index.md
@@ -0,0 +1,10 @@
+---
+layout: doc
+title: Web后端
+---
+
+# 📚 内容导航
+
+- [MySQL知识点](/Web-Backend/MySQL-Knowledge)
+- [Flyway简单使用](/Web-Backend/Flyway)
+- [MyBatis简介和使用](/Web-Backend/MyBatis)
\ No newline at end of file
diff --git a/docs/Web/index.md b/docs/Web/index.md
deleted file mode 100644
index 241cad6..0000000
--- a/docs/Web/index.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-layout: doc
-title: Web
----
-
-# 📚 内容导航
-
-- [MySQL知识点](/Web/MySQL-Knowledge)
diff --git a/docs/index.md b/docs/index.md
index a7a51cb..25b9c24 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -2,28 +2,28 @@
layout: home
hero:
- name: "Cxx0822知识库"
- text: "技术成长之路"
- tagline: 记录学习笔记 | 分享开发经验 | 构建知识体系
- # actions:
- # - theme: brand
- # text: 开始探索
- # link: /web/
- # - theme: alt
- # text: GitHub
- # link: https://github.com/你的用户名
+ name: "Cxx0822"
+ text: "拾光记"
+ tagline: 书山有路勤为径 | 学海无涯苦作舟
+ image:
+ src: /logo.png
+ alt: VitePress
+ actions:
+ - theme: brand
+ text: Web后端
+ link: /Web-Backend/
+ - theme: brand
+ text: DevOps
+ link: /DevOps/
+ - theme: brand
+ text: SpringBoot
+ link: /SpringBoot/
features:
- - title: 📚 系统学习
- details: 从基础到进阶,系统整理开发知识体系,帮助构建完整的技能树
- - title: 💻 实战笔记
- details: 记录项目开发中的实际问题与解决方案,包含代码示例和最佳实践
- title: 🚀 技术分享
details: 分享新技术探索、性能优化、架构设计等深度技术内容
- title: 📝 持续更新
details: 知识库持续维护更新,跟随技术发展趋势,保持内容的新鲜度
- title: 🔍 快速检索
details: 清晰的分类导航和搜索功能,方便快速定位所需的技术知识点
- - title: 🌱 成长记录
- details: 记录个人技术成长的每一个阶段,见证从新手到专家的蜕变过程
---
diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico
new file mode 100644
index 0000000..79fce71
Binary files /dev/null and b/docs/public/favicon.ico differ
diff --git a/docs/public/logo.png b/docs/public/logo.png
new file mode 100644
index 0000000..f02308b
Binary files /dev/null and b/docs/public/logo.png differ