feat:增加字体
This commit is contained in:
@@ -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: '最后更新于'
|
||||
}
|
||||
|
||||
27
docs/.vitepress/theme/components/CustomComponent.vue
Normal file
27
docs/.vitepress/theme/components/CustomComponent.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="custom-component">
|
||||
<h3>{{ title }}</h3>
|
||||
<p>{{ description }}</p>
|
||||
<button @click="count++">点击次数: {{ count }}</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
description: String
|
||||
})
|
||||
|
||||
const count = ref(0)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-component {
|
||||
border: 1px solid #e2e2e2;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
</style>
|
||||
BIN
docs/.vitepress/theme/fonts/custom.woff2
Normal file
BIN
docs/.vitepress/theme/fonts/custom.woff2
Normal file
Binary file not shown.
12
docs/.vitepress/theme/index.ts
Normal file
12
docs/.vitepress/theme/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
|
||||
import '../theme/style.css'
|
||||
|
||||
// 定义组件导入的类型
|
||||
interface ComponentModule {
|
||||
default: any
|
||||
}
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme
|
||||
}
|
||||
19
docs/.vitepress/theme/style.css
Normal file
19
docs/.vitepress/theme/style.css
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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,选择刚才的数据视图即可查看该视图下所有数据。
|
||||
|
||||
@@ -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的形式,不知道是什么原因?
|
||||
|
||||
# 二、创建工程
|
||||
|
||||
@@ -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)
|
||||
72
docs/SpringBoot/SpringBoot3-GraalVM.md
Normal file
72
docs/SpringBoot/SpringBoot3-GraalVM.md
Normal file
@@ -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
|
||||
<plugins>
|
||||
<!-- 将项目打包成可执行的 JAR/WAR 文件 -->
|
||||
<!-- repackage目标会替换 Maven 默认的打包行为 -->
|
||||
<!-- 使 JAR/WAR 文件包含所有依赖项,成为一个独立运行的应用 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
<!-- 执行 AOT 编译 -->
|
||||
<goal>process-aot</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- GraalVM Native Maven 插件 -->
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>0.10.2</version>
|
||||
<configuration>
|
||||
<buildArgs combine.children="append">
|
||||
<!-- 支持 http 协议 -->
|
||||
<buildArg>--enable-url-protocols=http</buildArg>
|
||||
<!-- 用于解决数据库中文乱码问题 -->
|
||||
<buildArg>-H:+AddAllCharsets</buildArg>
|
||||
</buildArgs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
<goal>compile-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
```
|
||||
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)
|
||||
60
docs/SpringBoot/SpringBootBean.md
Normal file
60
docs/SpringBoot/SpringBootBean.md
Normal file
@@ -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,通过组件扫描自动注册。<br>无特定语义,是其他组件注解的基础。 | - Bean 生命周期管理<br>- 依赖注入支持 |
|
||||
| **@Repository** | 标记数据访问组件(如数据库操作类),<br>自动处理数据访问异常。 | - 异常转换<br>- DAO 组件扫描 |
|
||||
| **@Service** | 标记业务逻辑组件,负责处理业务流程、事务管理等。<br>提供语义化,明确该类在架构中的角色。 | - 与 @Transactional 注解默认集成<br>- IDE 识别为服务层组件 |
|
||||
| **@Controller** | 标记 Web 控制器,处理 HTTP 请求。<br>与 Spring MVC 框架紧密集成。 | - 请求映射自动注册<br>- 支持 @RequestMapping、@GetMapping 等注解<br>- 视图解析(返回视图名称或 JSON) |
|
||||
| **@RestController** | @Controller + @ResponseBody 的组合,专门用于 RESTful API,直接返回 JSON/XML 等数据。 | - 所有方法默认返回 JSON/XML(无需每个方法添加 @ResponseBody) |
|
||||
105
docs/SpringBoot/SpringBootStarter.md
Normal file
105
docs/SpringBoot/SpringBootStarter.md
Normal file
@@ -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
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
89
docs/SpringBoot/SpringMVC.md
Normal file
89
docs/SpringBoot/SpringMVC.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 一、基础概念
|
||||
  Spring MVC(Spring Model-View-Controller)是 Spring Framework 中的一部分,它是一个基于 **<font style="color:#DF2A3F;">请求驱动</font>** 的 Web 框架,主要用于构建 Web 应用程序,并且遵循 MVC(模型-视图-控制器) 设计模式。它将 Web 应用的业务逻辑、用户界面和请求处理分离,使得代码更加模块化和可维护。
|
||||
|
||||
# 二、具体流程
|
||||

|
||||
|
||||
1. **客户端发起HTTP请求**
|
||||
|
||||
  客户端(浏览器、API 客户端等)向服务器发送 HTTP 请求。请求包含了目标 URL、HTTP 方法(GET、POST 等)以及可能的请求参数。
|
||||
前端通过发送 HTTP 请求(通常是 AJAX 请求)到后端的 API 端点,并期望获得响应(通常是 JSON 数据)。
|
||||
|
||||
2. **请求到达 DispatcherServlet**
|
||||
|
||||
  所有 HTTP 请求都会先到达 Spring MVC 的核心组件:**<font style="color:#DF2A3F;">DispatcherServlet</font>**。它是前端控制器,负责将请求分发给正确的处理器。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:视图渲染完成后。
|
||||
  **<font style="color:#DF2A3F;">如果拦截器的 preHandle 方法返回 false,请求会被拦截,后续的处理不会继续进行。</font>**
|
||||
|
||||
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:是一个全局异常处理器,用于捕获应用中所有控制器抛出的异常。
|
||||
@@ -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)
|
||||
57
docs/Web-Backend/Flyway.md
Normal file
57
docs/Web-Backend/Flyway.md
Normal file
@@ -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
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 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<Version>__<Description>.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表中。
|
||||
453
docs/Web-Backend/MyBatis.md
Normal file
453
docs/Web-Backend/MyBatis.md
Normal file
@@ -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
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>x.x.x</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
  可以在Github中查看[MyBatis](https://github.com/mybatis/mybatis-3)最新版本号。
|
||||
|
||||
### 2.2 配置文件
|
||||
  在`resource`文件夹中新建mybatis-config.xml文件和mapper->BlogMapper.xml映射文件:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
<configuration>
|
||||
<!-- 环境配置 -->
|
||||
<environments default="development">
|
||||
<!-- 环境名称 -->
|
||||
<environment id="development">
|
||||
<!-- 事务管理器配置 -->
|
||||
<transactionManager type="JDBC"/>
|
||||
<!-- 数据源配置 -->
|
||||
<dataSource type="POOLED">
|
||||
<!-- JDBC驱动名称 -->
|
||||
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
|
||||
<!-- 数据库地址 -->
|
||||
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_learn?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"/>
|
||||
<!-- 数据库用户名 -->
|
||||
<property name="username" value="root"/>
|
||||
<!-- 数据库密码-->
|
||||
<property name="password" value="123456"/>
|
||||
</dataSource>
|
||||
</environment>
|
||||
</environments>
|
||||
|
||||
<!-- 映射器 -->
|
||||
<mappers>
|
||||
<!-- mapper文件 -->
|
||||
<mapper resource="mapper/BlogMapper.xml"/>
|
||||
</mappers>
|
||||
</configuration>
|
||||
```
|
||||
|
||||
  注:如果使用MySql数据库,需要增加MySql驱动依赖:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.12</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 2.3 定义映射语句
|
||||
  新建dao->BlogDao.java:
|
||||
|
||||
```java
|
||||
public interface BlogDao {
|
||||
Blog selectBlog(@Param("id") Integer id);
|
||||
}
|
||||
```
|
||||
|
||||
  BlogMapper.xml:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.example.mybatislearn.dao.BlogDao">
|
||||
<select id="selectBlog" resultType="com.example.mybatislearn.entity.Blog">
|
||||
select * from Blog where author_id = #{id}
|
||||
</select>
|
||||
</mapper>
|
||||
```
|
||||
|
||||
### 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
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 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
|
||||
<sql id="userColumns">
|
||||
id, username, email, phone
|
||||
</sql>
|
||||
|
||||
<select id="findAllUsers" resultType="User">
|
||||
SELECT <include refid="userColumns" /> FROM users
|
||||
</select>
|
||||
```
|
||||
|
||||
## 4.3 批量操作
|
||||
  推荐使用集合方式批量操作:
|
||||
|
||||
```java
|
||||
@Mapper
|
||||
public interface UserMapper {
|
||||
Integer insertUsers(@Param("list") List<User> userList);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```xml
|
||||
<insert id="insertUsers">
|
||||
INSERT INTO user (username, password)
|
||||
VALUES
|
||||
<foreach collection ="list" item="item" separator =",">
|
||||
(#{item.username}, #{item.password})
|
||||
</foreach>
|
||||
</insert>
|
||||
```
|
||||
|
||||
## 4.4 结果映射
|
||||
  复杂结果缓存
|
||||
|
||||
```xml
|
||||
<!-- 非常复杂的结果映射 -->
|
||||
<resultMap id="detailedBlogResultMap" type="Blog">
|
||||
<!-- 一般不需要 -->
|
||||
<constructor>
|
||||
<idArg column="blog_id" javaType="int"/>
|
||||
</constructor>
|
||||
<result property="title" column="blog_title"/>
|
||||
<!-- 复杂对象 1对1 -->
|
||||
<association property="author" javaType="Author">
|
||||
<id property="id" column="author_id"/>
|
||||
<result property="username" column="author_username"/>
|
||||
<result property="password" column="author_password"/>
|
||||
<result property="email" column="author_email"/>
|
||||
<result property="bio" column="author_bio"/>
|
||||
<result property="favouriteSection" column="author_favourite_section"/>
|
||||
</association>
|
||||
<!-- 列表 1对多-->
|
||||
<collection property="posts" ofType="Post">
|
||||
<id property="id" column="post_id"/>
|
||||
<result property="subject" column="post_subject"/>
|
||||
<association property="author" javaType="Author"/>
|
||||
<collection property="comments" ofType="Comment">
|
||||
<id property="id" column="comment_id"/>
|
||||
</collection>
|
||||
<collection property="tags" ofType="Tag" >
|
||||
<id property="id" column="tag_id"/>
|
||||
</collection>
|
||||
<discriminator javaType="int" column="draft">
|
||||
<case value="1" resultType="DraftPost"/>
|
||||
</discriminator>
|
||||
</collection>
|
||||
</resultMap>
|
||||
```
|
||||
|
||||
  其中`<collection>`也可以使用嵌套查询:
|
||||
|
||||
```xml
|
||||
<collection property="posts" ofType="Post" select="queryPost"/>
|
||||
|
||||
<resultMap id="postResultMap" type="Post">
|
||||
<id property="id" column="post_id"/>
|
||||
<result property="subject" column="post_subject"/>
|
||||
<association property="author" javaType="Author"/>
|
||||
<collection property="comments" ofType="Comment">
|
||||
<id property="id" column="comment_id"/>
|
||||
</collection>
|
||||
<collection property="tags" ofType="Tag" >
|
||||
<id property="id" column="tag_id"/>
|
||||
</collection>
|
||||
<discriminator javaType="int" column="draft">
|
||||
<case value="1" resultType="DraftPost"/>
|
||||
</discriminator>
|
||||
</resultMap>
|
||||
|
||||
<select id="queryPost" resultMap="postResultMap">
|
||||
|
||||
</select>
|
||||
|
||||
```
|
||||
|
||||
  如果需要传递参数,可以在`<collection>`添加`column`属性:
|
||||
|
||||
```xml
|
||||
<!-- 单个参数 -->
|
||||
<collection property="posts" column="name" ofType="Post" select="queryPost"/>
|
||||
<!-- 多个参数 -->
|
||||
<collection property="posts" column="{param1=param_1, param2=param_2}" ofType="Post" select="queryPost"/>
|
||||
```
|
||||
|
||||
  注:建立在非列表数据时使用嵌套查询,否则每查到一个数据都会进行一次子查询操作。
|
||||
|
||||
## 4.5 一二级缓存
|
||||
  默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:<cache/>
|
||||
|
||||
+ 映射语句文件中的所有 select 语句的结果将会被缓存。
|
||||
+ 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
|
||||
+ 一级缓存和二级缓存区别在于一级缓存只针对一次SqlSession,二级缓存针对全局范围。
|
||||
|
||||
## 4.6 动态SQL
|
||||
+ if :是/否
|
||||
|
||||
```xml
|
||||
<select id="findActiveBlogWithTitleLike" resultType="Blog">
|
||||
SELECT * FROM BLOG
|
||||
WHERE state = 'ACTIVE'
|
||||
<if test="title != null">
|
||||
AND title like #{title}
|
||||
</if>
|
||||
</select>
|
||||
```
|
||||
|
||||
+ choose、when、otherwise:选择其中一个
|
||||
|
||||
```xml
|
||||
<select id="findActiveBlogLike" resultType="Blog">
|
||||
SELECT * FROM BLOG WHERE state = 'ACTIVE'
|
||||
<choose>
|
||||
<when test="title != null">
|
||||
AND title like #{title}
|
||||
</when>
|
||||
<when test="author != null and author.name != null">
|
||||
AND author_name like #{author.name}
|
||||
</when>
|
||||
<otherwise>
|
||||
AND featured = 1
|
||||
</otherwise>
|
||||
</choose>
|
||||
</select>
|
||||
```
|
||||
|
||||
+ where、set:解决SQL语法问题
|
||||
|
||||
```xml
|
||||
<select id="findActiveBlogLike" resultType="Blog">
|
||||
SELECT * FROM BLOG
|
||||
<where>
|
||||
<if test="state != null">
|
||||
state = #{state}
|
||||
</if>
|
||||
<if test="title != null">
|
||||
AND title like #{title}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<update id="updateAuthorIfNecessary">
|
||||
update Author
|
||||
<set>
|
||||
<if test="username != null">username=#{username},</if>
|
||||
<if test="password != null">password=#{password},</if>
|
||||
</set>
|
||||
where id=#{id}
|
||||
</update>
|
||||
```
|
||||
|
||||
  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<String> {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -2,39 +2,39 @@
|
||||
## 一、基础知识
|
||||
### 1.1 数据类型
|
||||
#### 1.1.1 汇总
|
||||
|类型|存储空间|范围|适用场景|备注|
|
||||
| :-------------------------------------------------------------------------------------------------: | :-----------------: | :--------------------------: | :-----------------------: | :------------------------------------: |
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">TINYINT</span>|1字节|-128 \~ 127|状态码、年龄、布尔值||
|
||||
|类型|存储空间|范围|适用场景|
|
||||
| :-------------------------------------------------------------------------------------------------: | :-----------------: | :--------------------------: | :-----------------------: |
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">TINYINT</span>|1字节|-128 \~ 127|状态码、年龄、布尔值|
|
||||
|SMALLINT|2字节|-32,768 \~ 32,767|小范围计数、年份||
|
||||
|MEDIUMINT|3字节|-8,388,608 \~ 8,388,607|中型ID、访问量统计||
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">INT/INTEGER</span>|4字节|-2\^31 \~ 2\^31-1|用户ID、订单号(常用)||
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">BIGINT</span>|8字节|-2\^63 \~ 2\^63-1|分布式ID、大数据量计数||
|
||||
|MEDIUMINT|3字节|-8,388,608 \~ 8,388,607|中型ID、访问量统计|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">INT/INTEGER</span>|4字节|-2\^31 \~ 2\^31-1|用户ID、订单号(常用)|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">BIGINT</span>|8字节|-2\^63 \~ 2\^63-1|分布式ID、大数据量计数|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">DECIMAL(M,D)</span>|变长(M+2字节)||金融金额、精确计算|精确小数,M\=总位数,D\=小数位|
|
||||
|FLOAT|4字节||科学测量、非精确计算|单精度浮点,约6-7位有效数字|
|
||||
|DOUBLE|8字节||地理坐标、高精度计算|双精度浮点,约15位有效数字|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">CHAR(M)</span>|255字符||固定长度编码、MD5哈希||
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">VARCHAR(M)</span>|65,535字节||用户名、地址等变长数据||
|
||||
|TINYTEXT|255字节||短标题、简介||
|
||||
|TEXT|65,535字节||文章内容、评论||
|
||||
|MEDIUMTEXT|16MB (2\^24-1)||博客文章、产品描述||
|
||||
|LONGTEXT|4GB (2\^32-1)||电子书、大型文档||
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">DATE</span>|||纯日期||
|
||||
|TIME(fsp)|||可指定微秒精度(0-6)||
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">DATETIME(fsp)</span>|||高精度时间记录||
|
||||
|TIMESTAMP(fsp)|||自动时区转换,4字节存储||
|
||||
|FLOAT|4字节||科学测量、非精确计算|
|
||||
|DOUBLE|8字节||地理坐标、高精度计算|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">CHAR(M)</span>|255字符||固定长度编码、MD5哈希|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">VARCHAR(M)</span>|65,535字节||用户名、地址等变长数据|
|
||||
|TINYTEXT|255字节||短标题、简介|
|
||||
|TEXT|65,535字节||文章内容、评论|
|
||||
|MEDIUMTEXT|16MB (2\^24-1)||博客文章、产品描述|
|
||||
|LONGTEXT|4GB (2\^32-1)||电子书、大型文档|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">DATE</span>|||纯日期|
|
||||
|TIME(fsp)|||可指定微秒精度(0-6)|
|
||||
|<span data-type="text" style="background-color: var(--b3-card-error-background); color: var(--b3-card-error-color);">DATETIME(fsp)</span>|||高精度时间记录|
|
||||
|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`等语句使用)进行分析,并输出该语句的执行计划。
|
||||
10
docs/Web-Backend/index.md
Normal file
10
docs/Web-Backend/index.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
layout: doc
|
||||
title: Web后端
|
||||
---
|
||||
|
||||
# 📚 内容导航
|
||||
|
||||
- [MySQL知识点](/Web-Backend/MySQL-Knowledge)
|
||||
- [Flyway简单使用](/Web-Backend/Flyway)
|
||||
- [MyBatis简介和使用](/Web-Backend/MyBatis)
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
layout: doc
|
||||
title: Web
|
||||
---
|
||||
|
||||
# 📚 内容导航
|
||||
|
||||
- [MySQL知识点](/Web/MySQL-Knowledge)
|
||||
@@ -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: 记录个人技术成长的每一个阶段,见证从新手到专家的蜕变过程
|
||||
---
|
||||
|
||||
BIN
docs/public/favicon.ico
Normal file
BIN
docs/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
docs/public/logo.png
Normal file
BIN
docs/public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 481 KiB |
Reference in New Issue
Block a user