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 @@ + + + + + \ 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容器日志是否有错误,正确的应该会有上传成功的提示。 ![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/a2cfe735a9245758daf6ea36a4c82f04.png '配置数据流.png') ### 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: ![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/352d69738b7325637e5716425757ac87.png '邮箱地址.png')   配置完模板和地址后,选择告警->添加告警,例如可以选择当有level='critical',并且出现1次时,触发报警,并通知到指定邮箱。 -![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/05200db676132fd43d3346099facee1b.png '邮箱告警.png') -  周期:监控数据的时间窗口范围,即每次检查告警条件时,回溯多长时间的监控数据。如果周期 = 5分钟:每次检查时,分析最近 5 分钟的日志/指标数据。 -  频率:告警规则检查的时间间隔,即每隔多久执行一次告警条件判断。 -  通知后静默:触发告警并发送通知后,系统暂时停止重复通知的时间。 -  也可以设置为实时告警,即当告警发生时就立即触发,不会有周期和频率参数设置。 +![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/05200db676132fd43d3346099facee1b.png '邮箱告警.png') +  周期:监控数据的时间窗口范围,即每次检查告警条件时,回溯多长时间的监控数据。如果周期 = 5分钟:每次检查时,分析最近 5 分钟的日志/指标数据。 +  频率:告警规则检查的时间间隔,即每隔多久执行一次告警条件判断。 +  通知后静默:触发告警并发送通知后,系统暂时停止重复通知的时间。 +  也可以设置为实时告警,即当告警发生时就立即触发,不会有周期和频率参数设置。 ### 3.3 配置WebHook -  首先配置模板和WebHook地址。 +  首先配置模板和WebHook地址。   打开控制台,选择右上角的设置按钮,选择模板->添加模板->Web Hook,填写Body: ```json { @@ -181,12 +190,12 @@ openobserve: ``` ![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/5c6514f9d689f55aa1bf74f75f5ea806.png 'WebHook模板.png') -  选择地址->添加地址->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。 ![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/d29ddbd369e32cb7c2770464e8d0a142.png 'API查看日志.png') ## 四、自定义日志告警服务 ![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/74d5efdb80f506395b81988258433d9d.png '日志框架.png') -  基本原理为通过提供一个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生命周期 +![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/b30628a6b1fa3cfd250cc5efff612a68.jpg 'Bean生命周期.jpg') + +### 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 应用的业务逻辑、用户界面和请求处理分离,使得代码更加模块化和可维护。 + +# 二、具体流程 +![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/04fb16a3e32f247bbf0bb7e176de8444.png '具体流程.png') + +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 前后端分离的架构。 + +# 三、完整流程 +![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/cad3b69253771b02b07d94f7d01c0e4f.png '完整流程.png') +  在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 作为索引结构。 ![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/91d2e40a1dae728c4061d1e1845e0ae3.png 'MySQL索引.png') -  例如要查找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