Skip to content

Commit

Permalink
add toc to markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
rbmonster committed Dec 10, 2020
1 parent 357cd75 commit fb9a29f
Show file tree
Hide file tree
Showing 30 changed files with 1,964 additions and 582 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Java线程](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/THREAD.md)
- [Java并发(虚拟机)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURRENT.md)
- [Java并发(AQS)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURRENTTOOL.md)
- [Java并发应用](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURREN_APPLICATION.md)

### Spring
- [Spring Basic(TODO)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/SPRING.md)
Expand All @@ -29,9 +30,17 @@
- [排序算法](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/SORT_ALGORITHM.md)

### 其他
- [MySQL](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/MYSQL.md)
- [MyBatis](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/MYBATIS.md)
- [计算机网络](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/NETWORK.md)

### 系统设计
- [接口设计](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/design/INTERFACE_DESIGN.md)
- [秒杀系统](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/design/SECONDS_KILL_DESIGN.md)
- [短连接](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/design/TINYURL.md)
- [抢红包(TODO)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/design/SECONDKILL_REDPACKAGE.md)
- [扫码登陆](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/design/SCAN_LOGIN.md)


## 记录平常学习java 的一些知识点
- [设计模式(head first)](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/CODEDESION_BOOK.md)
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/design/INTERFACE_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,17 @@ Content-Type: application/json
> 206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。
- 3xx(重定向类别)
> 301 永久重定向 :浏览器会存储重定向地址信息
> 302 临时重定向,HTTP1.0的状态码,HTTP1.1也有保留。
> 303临时重定向,HTTP1.1的状态码//
> 304 Not Modified表示客户端已在其缓存中有响应,因此无需再次传输相同的数据。
> 307临时重定向,HTTP1.1的状态码

- 4xx(客户端错误类别)

这些状态代码表示客户端已提出错误请求。
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/com/design/SCAN_LOGIN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 扫码登陆

相关文章:
- https://www.cnblogs.com/lidedong/p/9715200.html

主要为三部分的交互网页、app、服务端

## 流程
- 二维码扫码后的解析地址:
```
https://login.m.taobao.com/qrcodeCheck.htm?lgToken=2194021d239d0914a1002491f05a41c7&tbScanOpenType=Notification
```
1. 网页: 请求服务端获取二维码图片
2. 服务端: 服务器为这个会话生成一个全局唯一的ID,URL中lgToken就是这个ID。此时和浏览器建立长连接,实时监测二维码状态,定时去请求。
3. app:扫描二维码,app弹出提示框是否确认登陆。点击确认。
4. 服务端:获取到app端用户信息结合二维码的唯一ID,重新生成令牌。返回网页的登陆态。
5. 网页:收到服务端的登陆成功通知,存储对应的token信息。


## 实现细节
### 二维码
1. 二维码生成使用UUID的方案,生成后存储在redis,带上过期时间。
2. 二维码是否生效验证,直接验证redis是否有对应的数据。

- 新建:
```
content: {data: {qrCodeStatus: "NEW", resultCode: 100}, status: 0, success: true}
```

- 扫码成功
```
{"content":{"data":{"qrCodeStatus":"SCANED","resultCode":100},"status":0,"success":true},"hasError":false}
```

- 登陆认证成功使用307跳转
225 changes: 225 additions & 0 deletions src/main/java/com/learning/basic/MYSQL.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,228 @@ bin log 三种数据格式,主要区别于在存储bin log 的格式区别
WAL机制主要得益于两个方面:
1. redo log 和 binlog都是顺序写, 磁盘的顺序写比随机写速度要快;
2. 组提交机制, 可以大幅度降低磁盘的IOPS消耗。


## 实际sql的执行

### count(*)实现
不同引擎中的实现
- MyISAM引擎把一个表的总行数存在了磁盘上, 因此执行count(*)的时候会直接返回这个数,效率很高;
- 而InnoDB引擎就麻烦了, 它执行count(*)的时候, 需要把数据一行一行地从引擎里面读出来, 然后累积计数

InnoDB中Mysql对于count(*)的优化:InnoDB是索引组织表, 主键索引树的叶子节点是数据, 而普通索引树的叶子节点是主键值。 所以, 普通索引树比主键索引树小很多。 通索引树比主键索引树小很多。 对于count(*)这样的操作, 遍历哪个索引树得到的结果逻辑上都是一样的。 因此, MySQL优化器会找到最小的那棵树来遍历。 在保证逻辑正确的前提下, 尽量减少扫描的数据量, 是数据库系统设计的通用法则之一。

show table status 命令也可以显示行数,这里的行数是基于采样统计的,并不准确。

不同count的用法:count(*)、 count(主键id)、 count(字段)和count(1)
- count()是一个聚合函数, 对于返回的结果集, 一行行地判断, 如果count函数的参数不是NULL, 累计值就加1, 否则不加。 最后返回累计值
- 对于count(主键id)来说, InnoDB引擎会遍历整张表, 把每一行的id值都取出来, 返回给server层。 server层拿到id后, 判断是不可能为空的, 就按行累加。
- 对于count(1)来说, InnoDB引擎遍历整张表, 但不取值。 server层对于返回的每一行, 放一个数字“1”进去, 判断是不可能为空的, 按行累加。
- 对于count(字段)来说:
1. 如果这个“字段”是定义为not null的话, 一行行地从记录里面读出这个字段, 判断不能为null, 按行累加;
2. 如果这个“字段”定义允许为null, 那么执行的时候, 判断到有可能是null, 还要把值取出来再判断一下, 不是null才累加。
- count(*)是例外, 并不会把全部字段取出来, 而是专门做了优化, 不取值。 count(*)肯定不是null, 按行累加。
- 按照效率排序的话, count(字段)<count(主键id)<count(1)≈count(*)

### order by 处理流程
#### 全字段排序
```
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`city` varchar(16) NOT NULL,
`name` varchar(16) NOT NULL,
`age` int(11) NOT NULL,
`addr` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `city` (`city`)
) ENGINE=InnoDB;
select city,name,age from t where city='杭州' order by name limit 1000 ;
```
![image](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/mysql/picture/orderby1.jpg)
Extra这个字段中的“Using filesort”表示的就是需要排序, MySQL会给每个线程分配一块内存用于排序, 称为sort_buffer。
![image](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/mysql/picture/orderby2.jpg)
这个语句执行流程如下所示 :
1. 初始化sort_buffer, 确定放入name、 city、 age这三个字段;
2. 从索引city找到第一个满足city='杭州’条件的主键id, 也就是图中的ID_X;
3. 到主键id索引取出整行, 取name、 city、 age三个字段的值, 存入sort_buffer中;
4. 从索引city取下一个记录的主键id;
5. 重复步骤3、 4直到city的值不满足查询条件为止, 对应的主键id也就是图中的ID_Y;
6. 对sort_buffer中的数据按照字段name做快速排序;
7. 按照排序结果取前1000行返回给客户端

sort_buffer_size, 是MySQL为排序开辟的内存(sort_buffer) 的大小。 如果要排序的数据量小于sort_buffer_size, 排序就在内存中完成。 但如果排序数据量太大, 内存放不下, 则不得不利用磁盘临时文件辅助排序。
- sort_buffer_size大于了需要排序的数据量的大小, number_of_tmp_files就是0,排序直接在内存完成。

**optimizer_trace** 是一个跟踪功能,跟踪执行的语句的解析优化执行的过程,比explain更详细。
- number_of_tmp_files表示的是, 排序过程中使用的临时文件数。
- sort_mode: 表示参与排序的只有name和id这两个字段
- ```
/* 打开optimizer_trace, 只对本线程有效 */
SET optimizer_trace='enabled=on';
```
这里的排序使用的是归并排序
#### rowId排序
max_length_for_sort_data: 是MySQL中专门控制用于排序的行数据的长度的一个参数。 它的意思是, 如果单行的长度超过这个值, MySQL就认为单行太大, 要换一个算法。
![image](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/mysql/picture/orderby3.jpg)
- 主要体现在内存排序完毕之后要多一次查询。
对于InnoDB表来说, 执行全字段排序会减少磁盘访问, 因此会被优先选择。
在“InnoDB表”中,对于内存表,回表过程只是简单地根据数据行的位置, 直接访问内存得到数据, 根本不会导致多访问磁盘。
> 优化器会优先考虑的,就是用于排序的行越少越好。
order by rand()使用了内存临时表, 内存临时表排序的时候使用了rowid排序方法。
内存临时表与磁盘临时表
- tmp_table_size这个配置限制了内存临时表的大小, 默认值是16M。 如果临时表大小超过了tmp_table_size, 那么内存临时表就会转成磁盘临时表
直接使用order by rand(), 这个语句需要Using temporary和 Using filesort, 查询的执行代价往往是比较大的
### join的执行过程
#### Index Nested-Loop Join
```
select * from t1 straight_join t2 on (t1.a=t2.a);
```
执行流程是这样的:
1. 从表t1中读入一行数据 R;
2. 从数据行R中, 取出a字段到表t2里去查找;
3. 取出表t2中满足条件的行, 跟R组成一行, 作为结果集的一部分;
4. 重复执行步骤1到3, 直到表t1的末尾循环结束
- 实际执行的时候使用了BAK优化,将尽可能多的驱动表数据取出放Join Buffer中,再关联查询。
流程中:
1. 对驱动表t1做了全表扫描, 这个过程需要扫描100行;
2. 而对于每一行R, 根据a字段去表t2查找, 走的是树搜索过程。 由于我们构造的数据都是一一对应的, 因此每次的搜索过程都只扫描一行, 也是总共扫描100行;
3. 所以, 整个执行流程, 总扫描行数是200。
#### Simple Nested-Loop Join
```
select * from t1 straight_join t2 on (t1.a=t2.b);
```
- 表t2的字段b上没有索引,关联查询使用全表扫描。
- SQL请求就要扫描表t2多达100次, 总共扫描100*1000=10万行。
#### Block Nested-Loop Join
将驱动表数据读入线程内存join_buffer中,同样以全表扫描,但是因为使用内存操作,速度比上述方法快。
#### join语句mysql的优化
Multi-Range Read优化
- 大多数的数据都是按照主键递增顺序插入得到的, 所以可以认为, 如果按照主键的递增顺序查询的话, 对磁盘的读比较接近顺序读, 能够提升读性能
- MRR优化思路即将查询的关联集合排序,再关联查询,提高查询效率。将随机访问改成范围访问。
Batched Key Access (BAK)
- 将驱动表数据取出放join_buffer中,进行排序再关联查询。
- join_buffer内存不够大时,进行多次的重复操作。
#### 总结
1. 尽量使用被驱动表的索引,即关联表的字段为索引。
2. 不能使用被驱动表的索引, 只能使用Block Nested-Loop Join算法, 这样的语句就尽量不要使用;
3. 在使用join的时候, 应该让小表做驱动表。
4. 把join 的条件写在where和写在on中区别为,一个为连接的条件。
### union执行流程
```
(select 1000 as f) union (select id from t1 order by id desc limit 2);
```
![image](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/mysql/picture/union.jpg)
执行流程是这样的:
1. 创建一个内存临时表, 这个临时表只有一个整型字段f, 并且f是主键字段。
2. 执行第一个子查询, 得到1000这个值, 并存入临时表中。
3. 执行第二个子查询:拿到第一行id=1000, 试图插入临时表中。 但由于1000这个值已经存在于临时表了, 违反了唯一性约束, 所以插入失败, 然后继续执行;取到第二行id=999, 插入临时表成功。
4. 从临时表中按行取出数据, 返回结果, 并删除临时表, 结果中包含两行数据分别是1000和999
#### union all
```
(select 1000 as f) union all(select id from t1 order by id desc limit 2);
```
- 与上面的区别为union all不需要除重,因此直接把查询结果放在结果集中返回。
### group by 执行流程
```
select id%10 as m, count(*) as c from t1 group by m;
```
使用explain分析sql
- Using index, 表示这个语句使用了覆盖索引, 选择了索引a, 不需要回表;
- Using temporary, 表示使用了临时表;
- Using filesort, 表示需要文件排序。
这个语句的执行流程是这样的:
1. 创建内存临时表, 表里有两个字段m和c, 主键是m;
2. 扫描表t1的索引a, 依次取出叶子节点上的id值, 计算id%10的结果, 记为x;
1. 如果临时表中没有主键为x的行, 就插入一个记录(x,1);
2. 如果表中有主键为x的行, 就将x这一行的c值加1;
3. 遍历完成后, 再根据字段m做排序, 得到结果集返回给客户端。
group by语句默认都会对语句进行排序,可以使用order by null 避免group by 排序。
```
select id%10 as m, count(*) as c from t1 group by m order by null;
```
#### group by 优化 ——索引
索引保证了数据有序,在group by时候,分组计数计算时一片区域的id都是连续的,整个表扫描结束时便可以拿到结果,不需要临时表也不需要排序。
#### group by 优化 —— 直接排序
确保数据量确实超过了sort buffer,可以直接强制mysql直接使用磁盘文件排序。
```
select SQL_BIG_RESULT id%100 as m, count(*) as c from t1 group by m;
```
## 其他面试题
### mysql数据库抖动
- 当内存数据页跟磁盘数据页内容不一致的时候, 我们称这个内存页为“脏页”。
- 在内存数据写入到磁盘后, 内存和磁盘上的数据页的内容就一致了, 称为“干净页”。
Mysql 数据库抖动可能就是在刷“脏页”。两种触发刷脏页(flush)的方法
- 第一种:对应的就是InnoDB的redo log写满了。 这时候系统会停止所有更新操作, 把checkpoint往前推进, redo log留出空间可以继续写。
- 第二种:系统的内存需要新的内存页,这时候需要淘汰一些内存也。这如果是脏页,就会把脏页刷到内存中,然后淘汰脏页。
- 为什么不直接淘汰脏页,等新数据读取的时候再应用redo log? 主要为了保证状态统一,内存的数据存在则肯定是最新的,内存没有则文件肯定是最新的。
- 第三种:Mysql认为系统空闲时,刷脏页。
- 第四种:MySql关闭时刷脏页。
### 读已提交和可重复读是如何实现的
1. ReadView:
- 当进行查询操作时,事务会生成一个ReadView,ReadView是一个事务快照,准确来说是当前时间点系统内活跃的事务列表,也就是说系统内所有未提交的事务,都会记录在这个Readview内,事务就根据它来判断哪些数据是可见的,哪些是不可见的。
- 查询一条数据时,事务会拿到这个ReadView,去到undo log中进行判断。若查询到某一条数据:
2. undo log
- 当事务对数据行进行一次更新操作时,会把旧数据行记录在一个叫做undo log的记录中,在undo log中除了记录数据行,还会记录下该行数据的对应的创建版本号,也就是生成这行数据的事务id。并连接原纪录
### 读已提交和可重复读区别。
- 举两个事务线程的例子。
### 数据库数据库一致性是如何实现的?
- 通过redolog 与binlog 两阶段提交 保证事务一致性。
### redolog、undolog、binlog区别?
- redolog:确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
- undo log:保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
### 两种日志有以下三点不同。
1. redo log是InnoDB引擎特有的; binlog是MySQL的Server层实现的, 所有引擎都可以使用。
2. redo log是物理日志, 记录的是“在某个数据页上做了什么修改”; binlog是逻辑日志, 记录的是这个语句的原始逻辑, 比如“给ID=2这一行的c字段加1 ”。
3. redo log是循环写的, 空间固定会用完; binlog是可以追加写入的。 “追加写”是指binlog文件写到一定大小后会切换到下一个, 并不会覆盖以前的日志。
- binlog的作用?(说的是监控,其实主要是主从复制或者备份)
- 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
- 用于数据库的基于时间点的还原。
### 数据库什么情况会出现死锁?如何处理死锁?
mysql 两个事物更新条件互斥,进入循环等待。
使用mysql参数innodb_deadlock_detect设置为on, 表示开启这个死锁检测逻辑。
show processlist;显示哪些线程正在运行。您也可以使用mysqladmin processlist语句得到此信息
- 执行kill 命令
### 如何优化SQL
1. 通过慢查询日志获取sql语句
2. 对sql进行基本的优化,看是不是有用函数导致了索引不生效的情况。
3. 执行explain语句 查看SQL执行情况。
4. 针对未走索引的情况,可以使用强制走索引的方式
5. 针对复合索引创建顺序有误,导致了索引生效,修改索引。
6. 对于走错索引,说明mysql在统计行信息出错(由于磁盘,mysql使用采样统计的方式),通过执行analysis table。建议低峰使用。确定索引无用,可以删除干扰索引。第三种,强制走索引。。
7. 数据集过大,索引失效。
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
- Context是上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。


1. 何时使用
1. 何时使用
一个系统有许多类,而区分它们的只是他们直接的行为时

  2. 方法
Expand Down
Loading

0 comments on commit fb9a29f

Please sign in to comment.