diff --git a/README.md b/README.md
index 6bbcf89242e..e032124a105 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
点击订阅[Java面试进阶指南](https://xiaozhuanlan.com/javainterview?rel=javaguide)(专为Java面试方向准备)。[为什么要弄这个专栏?](https://shimo.im/docs/9BJjNsNg7S4dCnz3/)
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
@@ -17,10 +19,16 @@
Special Sponsors
-
-
+
+
+
+
+
推荐使用 https://snailclimb.top/JavaGuide/ 在线阅读(访问速度慢的话,请使用 https://snailclimb.gitee.io/javaguide ),在线阅读内容本仓库同步一致。这种方式阅读的优势在于:有侧边栏阅读体验更好,Gitee pages 的访问速度相对来说也比较快。
## 目录
@@ -69,7 +77,7 @@
### 容器
-* [常见面试题](docs/java/collection/Java集合框架常见面试题.md)
+* [Java容器常见面试题/知识点总结](docs/java/collection/Java集合框架常见面试题.md)
* [ArrayList 源码学习](docs/java/collection/ArrayList.md)
* [LinkedList 源码学习](docs/java/collection/LinkedList.md)
* [HashMap(JDK1.8)源码学习](docs/java/collection/HashMap.md)
@@ -128,7 +136,7 @@
### 算法
- [算法学习资源推荐](docs/dataStructures-algorithms/算法学习资源推荐.md)
-- [几道常见的子符串算法题总结 ](docs/dataStructures-algorithms/几道常见的子符串算法题.md)
+- [几道常见的字符串算法题总结 ](docs/dataStructures-algorithms/几道常见的子符串算法题.md)
- [几道常见的链表算法题总结 ](docs/dataStructures-algorithms/几道常见的链表算法题.md)
- [剑指offer部分编程题](docs/dataStructures-algorithms/剑指offer部分编程题.md)
- [公司真题](docs/dataStructures-algorithms/公司真题.md)
@@ -141,7 +149,7 @@
* [MySQL 学习与面试](docs/database/MySQL.md)
* [一千行MySQL学习笔记](docs/database/一千行MySQL命令.md)
* [MySQL高性能优化规范建议](docs/database/MySQL高性能优化规范建议.md)
-* [搞定数据库索引就是这么简单](docs/database/MySQL%20Index.md)
+* [数据库索引总结](docs/database/MySQL%20Index.md)
* [事务隔离级别(图文详解)](docs/database/事务隔离级别(图文详解).md)
* [一条SQL语句在MySQL中如何执行的](docs/database/一条sql语句在mysql中如何执行的.md)
diff --git a/docs/database/MySQL.md b/docs/database/MySQL.md
index 7fed73726d3..6840c982fde 100644
--- a/docs/database/MySQL.md
+++ b/docs/database/MySQL.md
@@ -1,9 +1,31 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [书籍推荐](#书籍推荐)
- [文字教程推荐](#文字教程推荐)
- [视频教程推荐](#视频教程推荐)
- [常见问题总结](#常见问题总结)
+ - [什么是MySQL?](#什么是mysql)
+ - [存储引擎](#存储引擎)
+ - [一些常用命令](#一些常用命令)
+ - [MyISAM和InnoDB区别](#myisam和innodb区别)
+ - [字符集及校对规则](#字符集及校对规则)
+ - [索引](#索引)
+ - [查询缓存的使用](#查询缓存的使用)
+ - [什么是事务?](#什么是事务)
+ - [事物的四大特性(ACID)](#事物的四大特性acid)
+ - [并发事务带来哪些问题?](#并发事务带来哪些问题)
+ - [事务隔离级别有哪些?MySQL的默认隔离级别是?](#事务隔离级别有哪些mysql的默认隔离级别是)
+ - [锁机制与InnoDB锁算法](#锁机制与innodb锁算法)
+ - [大表优化](#大表优化)
+ - [1. 限定数据的范围](#1-限定数据的范围)
+ - [2. 读/写分离](#2-读写分离)
+ - [3. 垂直分区](#3-垂直分区)
+ - [4. 水平分区](#4-水平分区)
+ - [一条SQL语句在MySQL中如何执行的](#一条sql语句在mysql中如何执行的)
+ - [MySQL高性能优化规范建议](#mysql高性能优化规范建议)
+ - [一条SQL语句执行得很慢的原因有哪些?](#一条sql语句执行得很慢的原因有哪些)
@@ -14,161 +36,270 @@
## 文字教程推荐
-[MySQL 教程(菜鸟教程)](http://www.runoob.com/mysql/mysql-tutorial.html)
+[MySQL 教程(菜鸟教程)](http://www.runoob.com/MySQL/MySQL-tutorial.html)
-[MySQL教程(易百教程)](https://www.yiibai.com/mysql/)
+[MySQL教程(易百教程)](https://www.yiibai.com/MySQL/)
## 视频教程推荐
**基础入门:** [与MySQL的零距离接触-慕课网](https://www.imooc.com/learn/122)
-**Mysql开发技巧:** [MySQL开发技巧(一)](https://www.imooc.com/learn/398) [MySQL开发技巧(二)](https://www.imooc.com/learn/427) [MySQL开发技巧(三)](https://www.imooc.com/learn/449)
+**MySQL开发技巧:** [MySQL开发技巧(一)](https://www.imooc.com/learn/398) [MySQL开发技巧(二)](https://www.imooc.com/learn/427) [MySQL开发技巧(三)](https://www.imooc.com/learn/449)
-**Mysql5.7新特性及相关优化技巧:** [MySQL5.7版本新特性](https://www.imooc.com/learn/533) [性能优化之MySQL优化](https://www.imooc.com/learn/194)
+**MySQL5.7新特性及相关优化技巧:** [MySQL5.7版本新特性](https://www.imooc.com/learn/533) [性能优化之MySQL优化](https://www.imooc.com/learn/194)
[MySQL集群(PXC)入门](https://www.imooc.com/learn/993) [MyCAT入门及应用](https://www.imooc.com/learn/951)
## 常见问题总结
-- ### ①存储引擎
-
- [MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇](https://juejin.im/post/5b1685bef265da6e5c3c1c34)
-
-- ### ②字符集及校对规则
-
- 字符集指的是一种从二进制编码到某类字符符号的映射。校对规则则是指某种字符集下的排序规则。Mysql中每一种字符集都会对应一系列的校对规则。
-
- Mysql采用的是类似继承的方式指定字符集的默认值,每个数据库以及每张数据表都有自己的默认值,他们逐层继承。比如:某个库中所有表的默认字符集将是该数据库所指定的字符集(这些表在没有指定字符集的情况下,才会采用默认字符集) PS:整理自《Java工程师修炼之道》
-
- 详细内容可以参考: [MySQL字符集及校对规则的理解](https://www.cnblogs.com/geaozhang/p/6724393.html#mysqlyuzifuji)
-
-- ### ③索引相关的内容(数据库使用中非常关键的技术,合理正确的使用索引可以大大提高数据库的查询性能)
-
- Mysql索引使用的数据结构主要有**BTree索引** 和 **哈希索引** 。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
-
- Mysql的BTree索引使用的是B数中的B+Tree,但对于主要的两种存储引擎的实现方式是不同的。
-
- **MyISAM:** B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
-
- **InnoDB:** 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。**在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。** **因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。** PS:整理自《Java工程师修炼之道》
-
- 详细内容可以参考:
-
- [干货:mysql索引的数据结构](https://www.jianshu.com/p/1775b4ff123a)
-
- [MySQL优化系列(三)--索引的使用、原理和设计优化](https://blog.csdn.net/Jack__Frost/article/details/72571540)
-
- [数据库两大神器【索引和锁】](https://juejin.im/post/5b55b842f265da0f9e589e79#comment)
-
-- ### ④查询缓存的使用
-
- my.cnf加入以下配置,重启Mysql开启查询缓存
- ```
- query_cache_type=1
- query_cache_size=600000
- ```
-
- Mysql执行以下命令也可以开启查询缓存
-
- ```
- set global query_cache_type=1;
- set global query_cache_size=600000;
- ```
- 如上,**开启查询缓存后在同样的查询条件以及数据情况下,会直接在缓存中返回结果**。这里的查询条件包括查询本身、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息。因此任何两个查询在任何字符上的不同都会导致缓存不命中。此外,如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、Mysql库中的系统表,其查询结果也不会被缓存。
-
- 缓存建立之后,Mysql的查询缓存系统会跟踪查询中涉及的每张表,如果这些表(数据或结构)发生变化,那么和这张表相关的所有缓存数据都将失效。
-
- **缓存虽然能够提升数据库的查询性能,但是缓存同时也带来了额外的开销,每次查询后都要做一次缓存操作,失效后还要销毁。** 因此,开启缓存查询要谨慎,尤其对于写密集的应用来说更是如此。如果开启,要注意合理控制缓存空间大小,一般来说其大小设置为几十MB比较合适。此外,**还可以通过sql_cache和sql_no_cache来控制某个查询语句是否需要缓存:**
- ```
- select sql_no_cache count(*) from usr;
- ```
-
-- ### ⑤事务机制
-
- **关系性数据库需要遵循ACID规则,具体内容如下:**
-
-
-
- 1. **原子性:** 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 2. **一致性:** 执行事务前后,数据库从一个一致性状态转换到另一个一致性状态。
- 3. **隔离性:** 并发访问数据库时,一个用户的事物不被其他事务所干扰,各并发事务之间数据库是独立的;
- 4. **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库 发生故障也不应该对其有任何影响。
-
- **为了达到上述事务特性,数据库定义了几种不同的事务隔离级别:**
-
-- **READ_UNCOMMITTED(未提交读):** 最低的隔离级别,允许读取尚未提交的数据变更,**可能会导致脏读、幻读或不可重复读**
-- **READ_COMMITTED(提交读):** 允许读取并发事务已经提交的数据,**可以阻止脏读,但是幻读或不可重复读仍有可能发生**
-- **REPEATABLE_READ(可重复读):** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,**可以阻止脏读和不可重复读,但幻读仍有可能发生。**
-- **SERIALIZABLE(串行):** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,**该级别可以防止脏读、不可重复读以及幻读**。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
-
- 这里需要注意的是:**Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.**
-
- 事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVCC(多版本并发控制),通过行的创建时间和行的过期时间来支持并发一致性读和回滚等特性。
-
- 详细内容可以参考: [可能是最漂亮的Spring事务管理详解](https://blog.csdn.net/qq_34337272/article/details/80394121)
-
-- ### ⑥锁机制与InnoDB锁算法
- **MyISAM和InnoDB存储引擎使用的锁:**
-
- - MyISAM采用表级锁(table-level locking)。
- - InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
-
- **表级锁和行级锁对比:**
-
- - **表级锁:** Mysql中锁定 **粒度最大** 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
- - **行级锁:** Mysql中锁定 **粒度最小** 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
-
- 详细内容可以参考:
- [Mysql锁机制简单了解一下](https://blog.csdn.net/qq_34337272/article/details/80611486)
-
- **InnoDB存储引擎的锁的算法有三种:**
- - Record lock:单个行记录上的锁
- - Gap lock:间隙锁,锁定一个范围,不包括记录本身
- - Next-key lock:record+gap 锁定一个范围,包含记录本身
-
- **相关知识点:**
- 1. innodb对于行的查询使用next-key lock
- 2. Next-locking keying为了解决Phantom Problem幻读问题
- 3. 当查询的索引含有唯一属性时,将next-key lock降级为record key
- 4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
- 5. 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1
-
-- ### ⑦大表优化
-
- 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
-
- 1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
- 2. **读/写分离:** 经典的数据库拆分方案,主库负责写,从库负责读;
- 3 . **垂直分区:**
-
- **根据数据库里面数据表的相关性进行拆分。** 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
-
- **简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。** 如下图所示,这样来说大家应该就更容易理解了。
- 
-
- **垂直拆分的优点:** 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
-
- **垂直拆分的缺点:** 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
-
- 4. **水平分区:**
-
-
- **保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。**
-
- 水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。
-
- 
-
- 水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 **水平拆分最好分库** 。
-
- 水平拆分能够 **支持非常大的数据量存储,应用端改造也少**,但 **分片事务难以解决** ,跨节点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 **尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度** ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
-
- **下面补充一下数据库分片的两种常见方案:**
- - **客户端代理:** **分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。** 当当网的 **Sharding-JDBC** 、阿里的TDDL是两种比较常用的实现。
- - **中间件代理:** **在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。** 我们现在谈的 **Mycat** 、360的Atlas、网易的DDB等等都是这种架构的实现。
-
-
- 详细内容可以参考:
- [MySQL大表优化方案](https://segmentfault.com/a/1190000006158186)
-
+### 什么是MySQL?
+
+MySQL 是一种关系型数据库,在Java企业级开发中非常常用,因为 MySQL 是开源免费的,并且方便扩展。阿里巴巴数据库系统也大量用到了 MySQL,因此它的稳定性是有保障的。MySQL是开放源代码的,因此任何人都可以在 GPL(General Public License) 的许可下下载并根据个性化的需要对其进行修改。MySQL的默认端口号是**3306**。
+
+### 存储引擎
+
+#### 一些常用命令
+
+**查看MySQL提供的所有存储引擎**
+
+```sql
+mysql> show engines;
+```
+
+
+
+从上图我们可以查看出 MySQL 当前默认的存储引擎是InnoDB,并且在5.7版本所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
+
+**查看MySQL当前默认的存储引擎**
+
+我们也可以通过下面的命令查看默认的存储引擎。
+
+```sql
+mysql> show variables like '%storage_engine%';
+```
+
+**查看表的存储引擎**
+
+```sql
+show table status like "table_name" ;
+```
+
+
+
+#### MyISAM和InnoDB区别
+
+MyISAM是MySQL的默认数据库引擎(5.5版之前)。虽然性能极佳,而且提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。不过,5.5版本之后,MySQL引入了InnoDB(事务性数据库引擎),MySQL 5.5版本后默认的存储引擎为InnoDB。
+
+大多数时候我们使用的都是 InnoDB 存储引擎,但是在某些情况下使用 MyISAM 也是合适的比如读密集的情况下。(如果你不介意 MyISAM 崩溃回复问题的话)。
+
+**两者的对比:**
+
+1. **是否支持行级锁** : MyISAM 只有表级锁(table-level locking),而InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。
+2. **是否支持事务和崩溃后的安全恢复: MyISAM** 强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。但是**InnoDB** 提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
+3. **是否支持外键:** MyISAM不支持,而InnoDB支持。
+4. **是否支持MVCC** :仅 InnoDB 支持。应对高并发事务, MVCC比单纯的加锁更高效;MVCC只在 `READ COMMITTED` 和 `REPEATABLE READ` 两个隔离级别下工作;MVCC可以使用 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统一。推荐阅读:[MySQL-InnoDB-MVCC多版本并发控制](https://segmentfault.com/a/1190000012650596)
+5. ......
+
+《MySQL高性能》上面有一句话这样写到:
+
+> 不要轻易相信“MyISAM比InnoDB快”之类的经验之谈,这个结论往往不是绝对的。在很多我们已知场景中,InnoDB的速度都可以让MyISAM望尘莫及,尤其是用到了聚簇索引,或者需要访问的数据都可以放入内存的应用。
+
+一般情况下我们选择 InnoDB 都是没有问题的,但是某事情况下你并不在乎可扩展能力和并发能力,也不需要事务支持,也不在乎崩溃后的安全恢复问题的话,选择MyISAM也是一个不错的选择。但是一般情况下,我们都是需要考虑到这些问题的。
+
+### 字符集及校对规则
+
+字符集指的是一种从二进制编码到某类字符符号的映射。校对规则则是指某种字符集下的排序规则。MySQL中每一种字符集都会对应一系列的校对规则。
+
+MySQL采用的是类似继承的方式指定字符集的默认值,每个数据库以及每张数据表都有自己的默认值,他们逐层继承。比如:某个库中所有表的默认字符集将是该数据库所指定的字符集(这些表在没有指定字符集的情况下,才会采用默认字符集) PS:整理自《Java工程师修炼之道》
+
+详细内容可以参考: [MySQL字符集及校对规则的理解](https://www.cnblogs.com/geaozhang/p/6724393.html#MySQLyuzifuji)
+
+### 索引
+
+MySQL索引使用的数据结构主要有**BTree索引** 和 **哈希索引** 。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
+
+MySQL的BTree索引使用的是B数中的B+Tree,但对于主要的两种存储引擎的实现方式是不同的。
+
+- **MyISAM:** B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
+- **InnoDB:** 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。**在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。** **因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。** PS:整理自《Java工程师修炼之道》
+
+**更多关于索引的内容可以查看文档首页MySQL目录下关于索引的详细总结。**
+
+### 查询缓存的使用
+
+> 执行查询语句的时候,会先查询缓存。不过,MySQL 8.0 版本后移除,因为这个功能不太实用
+
+my.cnf加入以下配置,重启MySQL开启查询缓存
+```properties
+query_cache_type=1
+query_cache_size=600000
+```
+
+MySQL执行以下命令也可以开启查询缓存
+
+```properties
+set global query_cache_type=1;
+set global query_cache_size=600000;
+```
+如上,**开启查询缓存后在同样的查询条件以及数据情况下,会直接在缓存中返回结果**。这里的查询条件包括查询本身、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息。因此任何两个查询在任何字符上的不同都会导致缓存不命中。此外,如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL库中的系统表,其查询结果也不会被缓存。
+
+缓存建立之后,MySQL的查询缓存系统会跟踪查询中涉及的每张表,如果这些表(数据或结构)发生变化,那么和这张表相关的所有缓存数据都将失效。
+
+**缓存虽然能够提升数据库的查询性能,但是缓存同时也带来了额外的开销,每次查询后都要做一次缓存操作,失效后还要销毁。** 因此,开启缓存查询要谨慎,尤其对于写密集的应用来说更是如此。如果开启,要注意合理控制缓存空间大小,一般来说其大小设置为几十MB比较合适。此外,**还可以通过sql_cache和sql_no_cache来控制某个查询语句是否需要缓存:**
+```sql
+select sql_no_cache count(*) from usr;
+```
+
+### 什么是事务?
+
+**事务是逻辑上的一组操作,要么都执行,要么都不执行。**
+
+事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
+
+### 事物的四大特性(ACID)
+
+
+
+1. **原子性:** 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
+2. **一致性:** 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
+3. **隔离性:** 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
+4. **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
+
+### 并发事务带来哪些问题?
+
+在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
+
+- **脏读(Dirty read):** 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
+- **丢失修改(Lost to modify):** 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
+- **不可重复读(Unrepeatableread):** 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
+- **幻读(Phantom read):** 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
+
+**不可重复度和幻读区别:**
+
+不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除比如多次读取一条记录发现记录增多或减少了。
+
+### 事务隔离级别有哪些?MySQL的默认隔离级别是?
+
+**SQL 标准定义了四个隔离级别:**
+
+- **READ-UNCOMMITTED(读取未提交):** 最低的隔离级别,允许读取尚未提交的数据变更,**可能会导致脏读、幻读或不可重复读**。
+- **READ-COMMITTED(读取已提交):** 允许读取并发事务已经提交的数据,**可以阻止脏读,但是幻读或不可重复读仍有可能发生**。
+- **REPEATABLE-READ(可重复读):** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,**可以阻止脏读和不可重复读,但幻读仍有可能发生**。
+- **SERIALIZABLE(可串行化):** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,**该级别可以防止脏读、不可重复读以及幻读**。
+
+------
+
+| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
+| :--------------: | :--: | :--------: | :----: |
+| READ-UNCOMMITTED | √ | √ | √ |
+| READ-COMMITTED | × | √ | √ |
+| REPEATABLE-READ | × | × | √ |
+| SERIALIZABLE | × | × | × |
+
+MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。我们可以通过`SELECT @@tx_isolation;`命令来查看
+
+```sql
+mysql> SELECT @@tx_isolation;
++-----------------+
+| @@tx_isolation |
++-----------------+
+| REPEATABLE-READ |
++-----------------+
+```
+
+这里需要注意的是:与 SQL 标准不同的地方在于 InnoDB 存储引擎在 **REPEATABLE-READ(可重读)**事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)** 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的**SERIALIZABLE(可串行化)**隔离级别。
+
+因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是**READ-COMMITTED(读取提交内容):**,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。
+
+InnoDB 存储引擎在 **分布式事务** 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。
+
+### 锁机制与InnoDB锁算法
+
+**MyISAM和InnoDB存储引擎使用的锁:**
+
+- MyISAM采用表级锁(table-level locking)。
+- InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
+
+**表级锁和行级锁对比:**
+
+- **表级锁:** MySQL中锁定 **粒度最大** 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
+- **行级锁:** MySQL中锁定 **粒度最小** 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
+
+详细内容可以参考: MySQL锁机制简单了解一下:[https://blog.csdn.net/qq_34337272/article/details/80611486](https://blog.csdn.net/qq_34337272/article/details/80611486)
+
+**InnoDB存储引擎的锁的算法有三种:**
+
+- Record lock:单个行记录上的锁
+- Gap lock:间隙锁,锁定一个范围,不包括记录本身
+- Next-key lock:record+gap 锁定一个范围,包含记录本身
+
+**相关知识点:**
+
+1. innodb对于行的查询使用next-key lock
+2. Next-locking keying为了解决Phantom Problem幻读问题
+3. 当查询的索引含有唯一属性时,将next-key lock降级为record key
+4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
+5. 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1
+
+### 大表优化
+
+当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
+
+#### 1. 限定数据的范围
+
+务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
+
+#### 2. 读/写分离
+
+经典的数据库拆分方案,主库负责写,从库负责读;
+
+#### 3. 垂直分区
+
+ **根据数据库里面数据表的相关性进行拆分。** 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
+
+ **简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。** 如下图所示,这样来说大家应该就更容易理解了。
+ 
+
+- **垂直拆分的优点:** 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
+- **垂直拆分的缺点:** 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
+
+#### 4. 水平分区
+
+**保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。**
+
+ 水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。
+
+
+
+水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 **水平拆分最好分库** 。
+
+水平拆分能够 **支持非常大的数据量存储,应用端改造也少**,但 **分片事务难以解决** ,跨节点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 **尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度** ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
+
+**下面补充一下数据库分片的两种常见方案:**
+
+- **客户端代理:** **分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。** 当当网的 **Sharding-JDBC** 、阿里的TDDL是两种比较常用的实现。
+- **中间件代理:** **在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。** 我们现在谈的 **Mycat** 、360的Atlas、网易的DDB等等都是这种架构的实现。
+
+详细内容可以参考: MySQL大表优化方案: [https://segmentfault.com/a/1190000006158186](https://segmentfault.com/a/1190000006158186)
+
+### 一条SQL语句在MySQL中如何执行的
+
+[一条SQL语句在MySQL中如何执行的]()
+
+### MySQL高性能优化规范建议
+
+[MySQL高性能优化规范建议]()
+
+### 一条SQL语句执行得很慢的原因有哪些?
+
+[腾讯面试:一条SQL语句执行得很慢的原因有哪些?---不看后悔系列](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485185&idx=1&sn=66ef08b4ab6af5757792223a83fc0d45&chksm=cea248caf9d5c1dc72ec8a281ec16aa3ec3e8066dbb252e27362438a26c33fbe842b0e0adf47&token=79317275&lang=zh_CN#rd)
+
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
+
\ No newline at end of file
diff --git "a/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md" "b/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md"
index 1e6f5816b74..67aad1cbed3 100644
--- "a/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md"
+++ "b/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md"
@@ -69,7 +69,7 @@
| REPEATABLE-READ | × | × | √ |
| SERIALIZABLE | × | × | × |
-MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。我们可以通过`SELECT @@tx_isolation;`命令来查看
+MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。我们可以通过`SELECT @@tx_isolation;`命令来查看,MySQL 8.0 该命令改为`SELECT @@transaction_isolation;`
```sql
mysql> SELECT @@tx_isolation;
diff --git "a/docs/essential-content-for-interview/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md" "b/docs/essential-content-for-interview/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md"
index b6f40fbc31b..00aaecd8c5b 100644
--- "a/docs/essential-content-for-interview/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md"
+++ "b/docs/essential-content-for-interview/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md"
@@ -1,3 +1,22 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
+
+
+- [何谓悲观锁与乐观锁](#何谓悲观锁与乐观锁)
+ - [悲观锁](#悲观锁)
+ - [乐观锁](#乐观锁)
+ - [两种锁的使用场景](#两种锁的使用场景)
+- [乐观锁常见的两种实现方式](#乐观锁常见的两种实现方式)
+ - [1. 版本号机制](#1-版本号机制)
+ - [2. CAS算法](#2-cas算法)
+- [乐观锁的缺点](#乐观锁的缺点)
+ - [1 ABA 问题](#1-aba-问题)
+ - [2 循环时间长开销大](#2-循环时间长开销大)
+ - [3 只能保证一个共享变量的原子操作](#3-只能保证一个共享变量的原子操作)
+- [CAS与synchronized的使用情景](#cas与synchronized的使用情景)
+
+
+
### 何谓悲观锁与乐观锁
> 乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。
@@ -64,8 +83,6 @@ JDK 1.5 以后的 `AtomicStampedReference 类`就提供了此种能力,其中
CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5开始,提供了`AtomicReference类`来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用`AtomicReference类`把多个共享变量合并成一个共享变量来操作。
-
-
### CAS与synchronized的使用情景
> **简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),synchronized适用于写比较多的情况下(多写场景,冲突一般较多)**
@@ -73,10 +90,17 @@ CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS
1. 对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。
2. 对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。
-
补充: Java并发编程这个领域中synchronized关键字一直都是元老级的角色,很久之前很多人都会称它为 **“重量级锁”** 。但是,在JavaSE 1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的 **偏向锁** 和 **轻量级锁** 以及其它**各种优化**之后变得在某些情况下并不是那么重了。synchronized的底层实现主要依靠 **Lock-Free** 的队列,基本思路是 **自旋后阻塞**,**竞争切换后继续竞争锁**,**稍微牺牲了公平性,但获得了高吞吐量**。在线程冲突较少的情况下,可以获得和CAS类似的性能;而线程冲突严重的情况下,性能远高于CAS。
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
+
diff --git "a/docs/java/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/java/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md"
index 4d70e1c1940..fc9fac22c0b 100644
--- "a/docs/java/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md"
+++ "b/docs/java/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [Servlet总结](#servlet总结)
diff --git "a/docs/java/Java IO\344\270\216NIO.md" "b/docs/java/Java IO\344\270\216NIO.md"
index 905df527c40..74bd850e696 100644
--- "a/docs/java/Java IO\344\270\216NIO.md"
+++ "b/docs/java/Java IO\344\270\216NIO.md"
@@ -27,12 +27,12 @@
**(1) 按操作方式分类结构图:**
-
+
**(2)按操作对象分类结构图**
-
+
### [二 java IO体系的学习总结](https://blog.csdn.net/nightcurtis/article/details/51324105)
1. **IO流的分类:**
@@ -92,7 +92,7 @@
- 写入数据到缓冲区(Writing Data to a Buffer)
**写数据到Buffer有两种方法:**
-
+
1.从Channel中写数据到Buffer
```java
int bytesRead = inChannel.read(buf); //read into buffer.
@@ -103,7 +103,7 @@
```
4. **Buffer常用方法测试**
-
+
说实话,NIO编程真的难,通过后面这个测试例子,你可能才能勉强理解前面说的Buffer方法的作用。
diff --git "a/docs/java/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/java/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
index 7e79094e283..94f39026af2 100644
--- "a/docs/java/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
+++ "b/docs/java/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [1. 面向对象和面向过程的区别](#1-面向对象和面向过程的区别)
@@ -60,7 +62,7 @@
## 1. 面向对象和面向过程的区别
- **面向过程** :**面向过程性能比面向对象高。** 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,**面向过程没有面向对象易维护、易复用、易扩展。**
-- **面向对象** :**面向对象易维护、易复用、易扩展。** 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,**面向过程性能比面向过程低**。
+- **面向对象** :**面向对象易维护、易复用、易扩展。** 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,**面向对象性能比面向过程低**。
## 2. Java 语言有哪些特点?
diff --git "a/docs/java/Java\347\274\226\347\250\213\350\247\204\350\214\203.md" "b/docs/java/Java\347\274\226\347\250\213\350\247\204\350\214\203.md"
index 0845c21b0a3..00c70a8ad27 100644
--- "a/docs/java/Java\347\274\226\347\250\213\350\247\204\350\214\203.md"
+++ "b/docs/java/Java\347\274\226\347\250\213\350\247\204\350\214\203.md"
@@ -1,5 +1,3 @@
-
-
根据各位建议加上了这部分内容,我暂时只是给出了两个资源,后续可能会对重要的点进行总结,然后更新在这里,如果你总结过这类东西,欢迎与我联系!
### 团队
diff --git a/docs/java/Multithread/AQS.md b/docs/java/Multithread/AQS.md
index a62f6d27a27..d1fe5df940c 100644
--- a/docs/java/Multithread/AQS.md
+++ b/docs/java/Multithread/AQS.md
@@ -1,5 +1,5 @@
-**目录:**
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
- [1 AQS 简单介绍](#1-aqs-简单介绍)
@@ -23,10 +23,6 @@
> 常见问题:AQS原理?;CountDownLatch和CyclicBarrier了解吗,两者的区别是什么?用过Semaphore吗?
-**本节思维导图:**
-
-
-
### 1 AQS 简单介绍
AQS的全称为(AbstractQueuedSynchronizer),这个类在java.util.concurrent.locks包下面。
@@ -471,3 +467,12 @@ CyclicBarrier和CountDownLatch的区别这部分内容参考了如下两篇文
ReentrantLock 和 synchronized 的区别在上面已经讲过了这里就不多做讲解。另外,需要注意的是:读写锁 ReentrantReadWriteLock 可以保证多个线程可以同时读,所以在读操作远大于写操作的时候,读写锁就非常有用了。
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
+
+
\ No newline at end of file
diff --git a/docs/java/Multithread/Atomic.md b/docs/java/Multithread/Atomic.md
index 1afb5f56511..05f4f2c9199 100644
--- a/docs/java/Multithread/Atomic.md
+++ b/docs/java/Multithread/Atomic.md
@@ -1,8 +1,28 @@
-> 个人觉得这一节掌握基本的使用即可!
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
-**本节思维导图:**
+> 个人觉得这一节掌握基本的使用即可!
-
+
+
+- [1 Atomic 原子类介绍](#1-atomic-原子类介绍)
+- [2 基本类型原子类](#2-基本类型原子类)
+ - [2.1 基本类型原子类介绍](#21-基本类型原子类介绍)
+ - [2.2 AtomicInteger 常见方法使用](#22-atomicinteger-常见方法使用)
+ - [2.3 基本数据类型原子类的优势](#23-基本数据类型原子类的优势)
+ - [2.4 AtomicInteger 线程安全原理简单分析](#24-atomicinteger-线程安全原理简单分析)
+- [3 数组类型原子类](#3-数组类型原子类)
+ - [3.1 数组类型原子类介绍](#31-数组类型原子类介绍)
+ - [3.2 AtomicIntegerArray 常见方法使用](#32-atomicintegerarray-常见方法使用)
+- [4 引用类型原子类](#4-引用类型原子类)
+ - [4.1 引用类型原子类介绍](#41--引用类型原子类介绍)
+ - [4.2 AtomicReference 类使用示例](#42-atomicreference-类使用示例)
+ - [4.3 AtomicStampedReference 类使用示例](#43-atomicstampedreference-类使用示例)
+ - [4.4 AtomicMarkableReference 类使用示例](#44-atomicmarkablereference-类使用示例)
+- [5 对象的属性修改类型原子类](#5-对象的属性修改类型原子类)
+ - [5.1 对象的属性修改类型原子类介绍](#51-对象的属性修改类型原子类介绍)
+ - [5.2 AtomicIntegerFieldUpdater 类使用示例](#52-atomicintegerfieldupdater-类使用示例)
+
+
### 1 Atomic 原子类介绍
@@ -12,7 +32,7 @@ Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是
并发包 `java.util.concurrent` 的原子类都存放在`java.util.concurrent.atomic`下,如下图所示。
-
+
根据操作的数据类型,可以将JUC包中的原子类分为4类
@@ -136,7 +156,7 @@ Thread-0 ------ currentValue=1, finalValue=2, compareAndSet Result=true
上面三个类提供的方法几乎相同,所以我们这里以 AtomicInteger 为例子来介绍。
**AtomicInteger 类常用方法**
-
+
```java
public final int get() //获取当前的值
public final int getAndSet(int newValue)//获取当前的值,并设置新的值
@@ -525,3 +545,12 @@ class User {
23
```
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
+
+
\ No newline at end of file
diff --git a/docs/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md b/docs/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md
index 23c7a518c4d..16ccbe19add 100644
--- a/docs/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md
+++ b/docs/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md
@@ -321,9 +321,9 @@ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}
```
-通过上面这些内容,我们足以通过猜测得出结论:**最终的变量是放在了当前线程的 `ThreadLocalMap` 中,并不是存在 `ThreadLocal` 上,ThreadLocal 可以理解为只是ThreadLocalMap的封装,传递了变量值。**
+通过上面这些内容,我们足以通过猜测得出结论:**最终的变量是放在了当前线程的 `ThreadLocalMap` 中,并不是存在 `ThreadLocal` 上,`ThreadLocal` 可以理解为只是`ThreadLocalMap`的封装,传递了变量值。** `ThrealLocal` 类中可以通过`Thread.currentThread()`获取到当前线程对象后,直接通过`getMap(Thread t)`可以访问到该线程的`ThreadLocalMap`对象。
-**每个`Thread`中都具备一个`ThreadLocalMap`,而`ThreadLocalMap`可以存储以`ThreadLocal`为key的键值对。这里解释了为什么每个线程访问同一个`ThreadLocal`,得到的确是不同的数值。另外,`ThreadLocal` 是 map结构是为了让每个线程可以关联多个 `ThreadLocal`变量。**
+**每个`Thread`中都具备一个`ThreadLocalMap`,而`ThreadLocalMap`可以存储以`ThreadLocal`为key的键值对。** 比如我们在同一个线程中声明了两个 `ThreadLocal` 对象的话,会使用 `Thread`内部都是使用仅有那个`ThreadLocalMap` 存放数据的,`ThreadLocalMap`的 key 就是 `ThreadLocal`对象,value 就是 `ThreadLocal` 对象调用`set`方法设置的值。`ThreadLocal` 是 map结构是为了让每个线程可以关联多个 `ThreadLocal`变量。这也就解释了 ThreadLocal 声明的变量为什么在每一个线程都有自己的专属本地变量。
`ThreadLocalMap`是`ThreadLocal`的静态内部类。
diff --git a/docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md b/docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md
index c96bc86dbba..75db37c9d02 100644
--- a/docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md
+++ b/docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md
@@ -294,7 +294,8 @@ Process finished with exit code 0
- 两者最主要的区别在于:**sleep 方法没有释放锁,而 wait 方法释放了锁** 。
- 两者都可以暂停线程的执行。
- Wait 通常被用于线程间交互/通信,sleep 通常被用于暂停执行。
-- wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify() 或者 notifyAll() 方法。sleep() 方法执行完成后,线程会自动苏醒。
+- wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify() 或者 notifyAll() 方法。sleep() 方法执行完成后,线程会自动苏醒。或者可以使用wait(long timeout)超时后线程会自动苏醒。
+
## 10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
diff --git "a/docs/java/Multithread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md" "b/docs/java/Multithread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
index 22873b3d9fd..645b279b121 100644
--- "a/docs/java/Multithread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
+++ "b/docs/java/Multithread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
@@ -1,3 +1,4 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
@@ -214,10 +215,18 @@ PriorityBlockingQueue 并发控制采用的是 **ReentrantLock**,队列为无
使用跳表实现Map 和使用哈希算法实现Map的另外一个不同之处是:哈希并不会保存元素的顺序,而跳表内所有的元素都是排序的。因此在对跳表进行遍历时,你会得到一个有序的结果。所以,如果你的应用需要有序性,那么跳表就是你不二的选择。JDK 中实现这一数据结构的类是ConcurrentSkipListMap。
-
-
## 七 参考
- 《实战Java高并发程序设计》
- https://javadoop.com/post/java-concurrent-queue
- https://juejin.im/post/5aeebd02518825672f19c546
+
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
+
+
\ No newline at end of file
diff --git a/docs/java/What's New in JDK8/Java8Tutorial.md b/docs/java/What's New in JDK8/Java8Tutorial.md
index 8bf59a6a686..9b473ea7d03 100644
--- a/docs/java/What's New in JDK8/Java8Tutorial.md
+++ b/docs/java/What's New in JDK8/Java8Tutorial.md
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
随着 Java 8 的普及度越来越高,很多人都提到面试中关于Java 8 也是非常常问的知识点。应各位要求和需要,我打算对这部分知识做一个总结。本来准备自己总结的,后面看到Github 上有一个相关的仓库,地址:
[https://github.com/winterbe/java8-tutorial](https://github.com/winterbe/java8-tutorial)。这个仓库是英文的,我对其进行了翻译并添加和修改了部分内容,下面是正文了。
@@ -916,9 +918,16 @@ System.out.println(hints2.length); // 2
@interface MyAnnotation {}
```
-
-
## Where to go from here?
关于Java 8的新特性就写到这了,肯定还有更多的特性等待发掘。JDK 1.8里还有很多很有用的东西,比如`Arrays.parallelSort`, `StampedLock`和`CompletableFuture`等等。
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。
+
+
\ No newline at end of file
diff --git "a/docs/java/What's New in JDK8/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md" "b/docs/java/What's New in JDK8/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md"
index 43e4539ccac..7de58352a5f 100644
--- "a/docs/java/What's New in JDK8/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md"
+++ "b/docs/java/What's New in JDK8/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md"
@@ -1,5 +1,3 @@
-
-
### 书籍
- **《Java8 In Action》**
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md" "b/docs/java/collection/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md"
index 57286ead27d..0e5d41033d9 100644
--- "a/docs/java/collection/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md"
+++ "b/docs/java/collection/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [剖析面试最常见问题之Java基础知识](#剖析面试最常见问题之java基础知识)
@@ -261,7 +263,7 @@ ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方
**JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点):**
-
+
## ConcurrentHashMap线程安全的具体实现方式/底层具体实现
diff --git "a/docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md" "b/docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md"
index b0bf10fb5d9..ad0a6545287 100644
--- "a/docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md"
+++ "b/docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [JDK 监控和故障处理工具总结](#jdk-监控和故障处理工具总结)
diff --git "a/docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md" "b/docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md"
index b73c5412667..7cd573d6022 100644
--- "a/docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md"
+++ "b/docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md"
@@ -1,3 +1,4 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
@@ -252,7 +253,7 @@ JDK1.2 以后,Java 对引用的概念进行了扩充,将引用分为强引
### 3.1 标记-清除算法
-算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它是最基础的收集算法,效率也很高,但是会带来两个明显的问题:
+该算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它是最基础的收集算法,后续的算法都是对其不足进行改进得到。这种垃圾收集算法会带来两个明显的问题:
1. **效率问题**
2. **空间问题(标记清除后会产生大量不连续的碎片)**
@@ -391,7 +392,15 @@ G1 收集器的运作大致分为以下几个步骤:
- https://my.oschina.net/hosee/blog/644618
-
+## 公众号
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。
+
+
diff --git "a/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md" "b/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md"
index 6b023f9a3ad..f944a6b2314 100644
--- "a/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md"
+++ "b/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [Java 内存区域详解](#java-内存区域详解)
@@ -52,7 +54,7 @@
## 一 概述
-对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像 C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。
+对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像 C/C++程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。
## 二 运行时数据区域
Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK. 1.8 和之前的版本略有不同,下面会介绍到。
@@ -203,7 +205,7 @@ JDK1.4 中新加入的 **NIO(New Input/Output) 类**,引入了一种基于**
### 3.1 对象的创建
下图便是 Java 对象的创建过程,我建议最好是能默写出来,并且要掌握每一步在做什么。
-
+
#### Step1:类加载检查
@@ -218,7 +220,7 @@ JDK1.4 中新加入的 **NIO(New Input/Output) 类**,引入了一种基于**
选择以上两种方式中的哪一种,取决于 Java 堆内存是否规整。而 Java 堆内存是否规整,取决于 GC 收集器的算法是"标记-清除",还是"标记-整理"(也称作"标记-压缩"),值得注意的是,复制算法内存也是规整的
-
+
**内存分配并发问题(补充内容,需要掌握)**
@@ -254,11 +256,12 @@ JDK1.4 中新加入的 **NIO(New Input/Output) 类**,引入了一种基于**
建立对象就是为了使用对象,我们的 Java 程序通过栈上的 reference 数据来操作堆上的具体对象。对象的访问方式有虚拟机实现而定,目前主流的访问方式有**①使用句柄**和**②直接指针**两种:
1. **句柄:** 如果使用句柄的话,那么 Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息;
-
+
+ 
2. **直接指针:** 如果使用直接指针访问,那么 Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而 reference 中存储的直接就是对象的地址。
-
+
**这两种对象访问方式各有优势。使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。**
@@ -306,7 +309,7 @@ System.out.println(str2==str3);//false
```java
String str1 = "str";
String str2 = "ing";
-
+
String str3 = "str" + "ing";//常量池中的对象
String str4 = str1 + str2; //在堆上创建的新的对象
String str5 = "string";//常量池中的对象
@@ -314,7 +317,7 @@ System.out.println(str2==str3);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
```
-
+
尽量避免多个字符串拼接,因为这样会重新创建对象。如果需要改变字符串的话,可以使用 StringBuilder 或者 StringBuffer。
### 4.2 String s1 = new String("abc");这句话创建了几个字符串对象?
@@ -418,3 +421,13 @@ i4=i5+i6 true
-
-
-
+
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
+
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。
+
+
diff --git "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md" "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md"
index fa93f93adfa..fe434252432 100644
--- "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md"
+++ "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [回顾一下类加载过程](#回顾一下类加载过程)
diff --git "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md"
index e08c5040a1b..97385002eee 100644
--- "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md"
+++ "b/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [类加载过程](#类加载过程)
@@ -78,7 +80,7 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚
- 《实战Java虚拟机》
-
-### 公众号
+## 公众号
如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
diff --git "a/docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md" "b/docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md"
index 2e427deb55c..7dfc9fb0258 100644
--- "a/docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md"
+++ "b/docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md"
@@ -1,3 +1,5 @@
+点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+
- [类文件结构](#类文件结构)
@@ -15,8 +17,6 @@
-> 公众号JavaGuide 后台回复关键字“1”,免费获取JavaGuide配套的Java工程师必备学习资源(文末有公众号二维码)。
-
# 类文件结构
## 一 概述
@@ -213,7 +213,7 @@ Class 文件存储格式中对方法的描述与对字段的描述几乎采用
-
- 《实战 Java 虚拟机》
-### 公众号
+## 公众号
如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
diff --git a/docs/operating-system/Shell.md b/docs/operating-system/Shell.md
index 9f3ae871ee4..0f11b0ae47d 100644
--- a/docs/operating-system/Shell.md
+++ b/docs/operating-system/Shell.md
@@ -272,7 +272,7 @@ for i in ${array[@]};do echo $i ;done # 遍历数组,数组元素为空,没
> 说明:图片来自《菜鸟教程》
Shell 编程支持下面几种运算符
-
+
- 算数运算符
- 关系运算符
- 布尔运算符
@@ -380,10 +380,10 @@ a 不等于 b
#!/bin/bash
a=3;
b=9;
-if [ $a = $b ]
+if [ $a -eq $b ]
then
echo "a 等于 b"
-elif [ $a > $b ]
+elif [ $a -gt $b ]
then
echo "a 大于 b"
else
@@ -394,7 +394,7 @@ fi
输出结果:
```
-a 大于 b
+a 小于 b
```
相信大家通过上面的示例就已经掌握了 shell 编程中的 if 条件语句。不过,还要提到的一点是,不同于我们常见的 Java 以及 PHP 中的 if 条件语句,shell if 条件语句中不能包含空语句也就是什么都不做的语句。
@@ -482,16 +482,20 @@ done
```shell
#!/bin/bash
-function(){
+hello(){
echo "这是我的第一个 shell 函数!"
}
-function
+echo "-----函数开始执行-----"
+hello
+echo "-----函数执行完毕-----"
```
输出结果:
```
+-----函数开始执行-----
这是我的第一个 shell 函数!
+-----函数执行完毕-----
```
diff --git a/docs/system-design/framework/spring/SpringInterviewQuestions.md b/docs/system-design/framework/spring/SpringInterviewQuestions.md
index b214ff502ed..9295681bfaa 100644
--- a/docs/system-design/framework/spring/SpringInterviewQuestions.md
+++ b/docs/system-design/framework/spring/SpringInterviewQuestions.md
@@ -42,7 +42,7 @@ Spring 官网列出的 Spring 的 6 个特征:

-- **Spring Core:** 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IOC 依赖注入功能。
+- **Spring Core:** 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注入功能。
- **Spring Aspects ** : 该模块为与AspectJ的集成提供支持。
- **Spring AOP** :提供了面向方面的编程实现。
- **Spring JDBC** : Java数据库连接。
@@ -57,16 +57,16 @@ Spring 官网列出的 Spring 的 6 个特征:
IoC(Inverse of Control:控制反转)是一种**设计思想**,就是 **将原本在程序中手动创建对象的控制权,交由Spring框架来管理。** IoC 在其他语言中也有应用,并非 Spirng 特有。 **IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。**
-将对象之间的相互依赖关系交给 IOC 容器来管理,并由 IOC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 **IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。** 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IOC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
+将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 **IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。** 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
推荐阅读:https://www.zhihu.com/question/23277575/answer/169698662
-**Spring IOC的初始化过程:**
-
+**Spring IoC的初始化过程:**
+
-IOC源码阅读
+IoC源码阅读
- https://javadoop.com/post/spring-ioc
@@ -288,4 +288,4 @@ public OneService getService(status) {
**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
-
\ No newline at end of file
+