Skip to content

Commit c59f765

Browse files
committed
update: Spring 部分内容完善
1 parent e3f51ce commit c59f765

File tree

3 files changed

+72
-30
lines changed

3 files changed

+72
-30
lines changed

docs/database/redis/redis-persistence.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ AOF 持久化功能的实现可以简单分为 5 步:
7171

7272
1. **命令追加(append)**:所有的写命令会追加到 AOF 缓冲区中。
7373
2. **文件写入(write)**:将 AOF 缓冲区的数据写入到 AOF 文件中。这一步需要调用`write`函数(系统调用),`write`将数据写入到了系统内核缓冲区之后直接返回了(延迟写)。注意!!!此时并没有同步到磁盘。
74-
3. **文件同步(fsync)**AOF 缓冲区根据对应的持久化方式( `fsync` 策略)向硬盘做同步操作。这一步需要调用 `fsync` 函数(系统调用)`fsync` 针对单个文件操作,对其进行强制硬盘同步,`fsync` 将阻塞直到写入磁盘完成后返回,保证了数据持久化。
74+
3. **文件同步(fsync)**这一步才是持久化的核心!根据你在 `redis.conf` 文件里 `appendfsync` 配置的策略,Redis 会在不同的时机,调用 `fsync` 函数(系统调用)`fsync` 针对单个文件操作,对其进行强制硬盘同步(文件在内核缓冲区里的数据写到硬盘)`fsync` 将阻塞直到写入磁盘完成后返回,保证了数据持久化。
7575
4. **文件重写(rewrite)**:随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
7676
5. **重启加载(load)**:当 Redis 重启时,可以加载 AOF 文件进行数据恢复。
7777

@@ -90,9 +90,9 @@ AOF 工作流程图如下:
9090

9191
在 Redis 的配置文件中存在三种不同的 AOF 持久化方式( `fsync`策略),它们分别是:
9292

93-
1. `appendfsync always`:主线程调用 `write` 执行写操作后,后台线程( `aof_fsync` 线程)立即会调用 `fsync` 函数同步 AOF 文件(刷盘)`fsync` 完成后线程返回,这样会严重降低 Redis 的性能(`write` + `fsync`
94-
2. `appendfsync everysec`:主线程调用 `write` 执行写操作后立即返回,由后台线程( `aof_fsync` 线程)每秒钟调用 `fsync` 函数(系统调用)同步一次 AOF 文件(`write`+`fsync``fsync`间隔为 1 秒)
95-
3. `appendfsync no`:主线程调用 `write` 执行写操作后立即返回,让操作系统决定何时进行同步,Linux 下一般为 30 秒一次(`write`但不`fsync``fsync` 的时机由操作系统决定)。
93+
1. `appendfsync always`:主线程调用 `write` 执行写操作后,会立刻调用 `fsync` 函数同步 AOF 文件(刷盘)。主线程会阻塞,直到 `fsync` 将数据完全刷到磁盘后才会返回。这种方式数据最安全,理论上不会有任何数据丢失。但因为每个写操作都会同步阻塞主线程,所以性能极差
94+
2. `appendfsync everysec`:主线程调用 `write` 执行写操作后立即返回,由后台线程( `aof_fsync` 线程)每秒钟调用 `fsync` 函数(系统调用)同步一次 AOF 文件(`write`+`fsync``fsync`间隔为 1 秒)。这种方式主线程的性能基本不受影响。在性能和数据安全之间做出了绝佳的平衡。不过,在 Redis 异常宕机时,最多可能丢失最近 1 秒内的数据。
95+
3. `appendfsync no`:主线程调用 `write` 执行写操作后立即返回,让操作系统决定何时进行同步,Linux 下一般为 30 秒一次(`write`但不`fsync``fsync` 的时机由操作系统决定)。 这种方式性能最好,因为避免了 `fsync` 的阻塞。但数据安全性最差,宕机时丢失的数据量不可控,取决于操作系统上一次同步的时间点。
9696

9797
可以看出:**这 3 种持久化方式的主要区别在于 `fsync` 同步 AOF 文件的时机(刷盘)**
9898

docs/database/sql/sql-questions-05.md

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,53 @@ tag:
4141
写法 1:
4242

4343
```sql
44-
SELECT exam_id,
45-
count(submit_time IS NULL OR NULL) incomplete_cnt,
46-
ROUND(count(submit_time IS NULL OR NULL) / count(*), 3) complete_rate
47-
FROM exam_record
48-
GROUP BY exam_id
49-
HAVING incomplete_cnt <> 0
44+
SELECT
45+
exam_id,
46+
(COUNT(*) - COUNT(submit_time)) AS incomplete_cnt,
47+
ROUND((COUNT(*) - COUNT(submit_time)) / COUNT(*), 3) AS incomplete_rate
48+
FROM
49+
exam_record
50+
GROUP BY
51+
exam_id
52+
HAVING
53+
(COUNT(*) - COUNT(submit_time)) > 0;
5054
```
5155

56+
利用 `COUNT(*) `统计分组内的总记录数,`COUNT(submit_time)` 只统计 `submit_time` 字段不为 NULL 的记录数(即已完成数)。两者相减,就是未完成数。
57+
5258
写法 2:
5359

5460
```sql
55-
SELECT exam_id,
56-
count(submit_time IS NULL OR NULL) incomplete_cnt,
57-
ROUND(count(submit_time IS NULL OR NULL) / count(*), 3) complete_rate
58-
FROM exam_record
59-
GROUP BY exam_id
60-
HAVING incomplete_cnt <> 0
61+
SELECT
62+
exam_id,
63+
COUNT(CASE WHEN submit_time IS NULL THEN 1 END) AS incomplete_cnt,
64+
ROUND(COUNT(CASE WHEN submit_time IS NULL THEN 1 END) / COUNT(*), 3) AS incomplete_rate
65+
FROM
66+
exam_record
67+
GROUP BY
68+
exam_id
69+
HAVING
70+
COUNT(CASE WHEN submit_time IS NULL THEN 1 END) > 0;
71+
```
72+
73+
使用 `CASE` 表达式,当条件满足时返回一个非 `NULL` 值(例如 1),否则返回 `NULL`。然后用 `COUNT` 函数来统计非 `NULL` 值的数量。
74+
75+
写法 3:
76+
77+
```sql
78+
SELECT
79+
exam_id,
80+
SUM(submit_time IS NULL) AS incomplete_cnt,
81+
ROUND(SUM(submit_time IS NULL) / COUNT(*), 3) AS incomplete_rate
82+
FROM
83+
exam_record
84+
GROUP BY
85+
exam_id
86+
HAVING
87+
incomplete_cnt > 0;
6188
```
6289

63-
两种写法都可以,只有中间的写法不一样,一个是对符合条件的才`COUNT`,一个是直接上`IF`,后者更为直观,最后这个`having`解释一下, 无论是 `complete_rate` 还是 `incomplete_cnt`,只要不为 0 即可,不为 0 就意味着有未完成的
90+
利用 `SUM` 函数对一个表达式求和。当 `submit_time``NULL` 时,表达式 `(submit_time IS NULL)` 的值为 1 (TRUE),否则为 0 (FALSE)。将这些 1 和 0 加起来,就得到了未完成的数量
6491

6592
### 0 级用户高难度试卷的平均用时和平均得分
6693

docs/system-design/framework/spring/spring-knowledge-and-questions-summary.md

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,29 +110,44 @@ Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程
110110

111111
## Spring IoC
112112

113-
### 谈谈自己对于 Spring IoC 的了解
113+
### 什么是 IoC?
114114

115-
**IoC(Inversion of Control:控制反转)** 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用
115+
IoC (Inversion of Control )即控制反转/反转控制。它是一种思想不是一个技术实现。描述的是:Java 开发领域对象的创建以及管理的问题
116116

117-
**为什么叫控制反转?**
117+
例如:现有类 A 依赖于类 B
118118

119-
- **控制**:指的是对象创建(实例化、管理)的权力
120-
- **反转**:控制权交给外部环境(Spring 框架IoC 容器)
119+
- **传统的开发方式** :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来
120+
- **使用 IoC 思想的开发方式** :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面去取即可。
121121

122-
![IoC 图解](https://oss.javaguide.cn/java-guide-blog/frc-365faceb5697f04f31399937c059c162.png)
122+
从以上两种开发方式的对比来看:我们 “丧失了一个权力” (创建、管理对象的权力),从而也得到了一个好处(不用再考虑对象的创建、管理等一系列的事情)
123123

124-
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
124+
**为什么叫控制反转?**
125125

126-
在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
126+
- **控制** :指的是对象创建(实例化、管理)的权力
127+
- **反转** :控制权交给外部环境(IoC 容器)
127128

128-
在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。
129+
![IoC 图解](https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/IoC&Aop-ioc-illustration.png)
129130

130-
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
131+
### IoC 解决了什么问题?
131132

132-
相关阅读:
133+
IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢?
133134

134-
- [IoC 源码阅读](https://javadoop.com/post/spring-ioc)
135-
- [IoC & AOP 详解(快速搞懂)](./ioc-and-aop.md)
135+
1. 对象之间的耦合度或者说依赖程度降低;
136+
2. 资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。
137+
138+
例如:现有一个针对 User 的操作,利用 Service 和 Dao 两层结构进行开发
139+
140+
在没有使用 IoC 思想的情况下,Service 层想要使用 Dao 层的具体实现的话,需要通过 new 关键字在`UserServiceImpl` 中手动 new 出 `IUserDao` 的具体实现类 `UserDaoImpl`(不能直接 new 接口类)。
141+
142+
很完美,这种方式也是可以实现的,但是我们想象一下如下场景:
143+
144+
开发过程中突然接到一个新的需求,针对`IUserDao` 接口开发出另一个具体实现类。因为 Server 层依赖了`IUserDao`的具体实现,所以我们需要修改`UserServiceImpl`中 new 的对象。如果只有一个类引用了`IUserDao`的具体实现,可能觉得还好,修改起来也不是很费力气,但是如果有许许多多的地方都引用了`IUserDao`的具体实现的话,一旦需要更换`IUserDao` 的实现方式,那修改起来将会非常的头疼。
145+
146+
![IoC&Aop-ioc-illustration-dao-service](https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/IoC&Aop-ioc-illustration-dao-service.png)
147+
148+
使用 IoC 的思想,我们将对象的控制权(创建、管理)交由 IoC 容器去管理,我们在使用的时候直接向 IoC 容器 “要” 就可以了
149+
150+
![](https://oss.javaguide.cn/github/javaguide/system-design/framework/spring/IoC&Aop-ioc-illustration-dao.png)
136151

137152
### 什么是 Spring Bean?
138153

0 commit comments

Comments
 (0)