水浅

  • Home

  • Tags14

  • Categories10

  • Search

数据库

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试

mysql

  • 数据库事务四大特性

    • 原子性
    • 隔离性
    • 一致性
    • 持久性
  • 数据库的索引

    • 脏读:事务B查看事务A 每天提交的数据
    • 不可重复读:一行被检索两次,并且该行,在不同的读取之时不同 其他会话修改数据
  • 读未提交 不可重复读 可重复读(默认) 串行化

  • 存储引擎:

    • 都是采用表级别锁
    • MYISAM: (非聚集索引)
      • 不支持外键 不提供事务 插入数据时 锁定整个表所以每次查询具有原子性
      • 可以直接读取行数变量
    • INNODB: (聚集索引)
      • 支持事务和行级别锁 聚集索引
      • 读取行数需要执行查询语句 MYSQl 5.5 之后默认是INNODB
    • 考虑存储引擎的几点
      • 是否支持事务
      • 是否读写频繁
      • 系统崩溃后 MyISAM恢复起来更困难
  • 数据库三大范式

    • 属性不可分 比如姓名 姓和名
    • 非主键属性完全依赖于主键属性: 比如学生id和姓名
    • 非主键属性是通过课程 ID 连接起来你不能通过ID 把他们弄在一起
  • 数据库的锁

    • 按照颗粒度来分的话

      • 行级别锁:
        • 开销大,加锁慢,会出现死锁。发生锁冲突的概率最低,并发度也最高。
        • 顾名思义就是对行进行加锁 他的颗粒粒度是最小的
        • 还有间隙锁 和
      • 表级别锁:
      • 开销小,加锁快,不会出现死锁。发生锁冲突的概率最高,并发度也最低。
        • 有两种锁
          • 读锁锁表
          • 写锁锁表
        • MYISAM 默认是加表锁的
        • INNODB 要加表说就需要显式的声明了
      • 页级锁
        • 是表锁和行锁中间隔离级别的一种锁
    • 按共享策略来分可以分为

      • 共享锁 读锁
      • 排他锁 写锁
      • 意向共享锁 意向排他锁的作用主要是快速判断一个表是否被上锁
    • 从加锁策略来分的 话可以分为

      • 乐观锁 默认对数据的操作是查询比较多 增删比较少

      • 悲观锁 默认修改多查询少 不加锁一定出问题

    • 其他还有一个自增锁 主要用于自增片段

mysql 索引

  • 索引算法
    • hash 算法实现 不能进行 范围查询 不能排序
    • B+ 索引
      • 聚集索引非聚集索引
      • 聚集索引 按索引的顺序存储 节点中存储正在的物理数据
      • 非聚集索引:存储指针 查询非指针数据时需要查询两次、
      • 为什么使用索引
      • 索引最大的好处是提高查询速度,
        缺点是更新数据时效率低,因为要同时更新索引
        对数据进行频繁查询进建立索引,如果要频繁更改数据不建议使用索引。
      • 为什么用B+ 树 他和B树的区别
      • B 所有节点都存储key和data 所有节点组成这颗树 叶子节点为空
      • B+ 只有叶子节点存储data 叶子节点包含了这棵树所有的键值 叶子节点不存储指针

数据库的主从复制

  • 为什么需要主从复制

    主从复制就是做一个备份的数据库,主数据库崩塌后可以立马切换到从数据库,避免数据丢失

  • 主从复制的原理

sql 优化

1
2
3
4
子查询变成left join
where代替having,having 检索完所有记录,才进行过滤
避免嵌套查询
对多个字段进行等值查询时,联合索引
1
2
3
// 通过ID 来过滤
select * from table limit 100000,20
select * from table where id > (select id from table limit 100000,1) limit 100000,20

索引失效的场景

- 未使用该列作为查询条件
- 使用like通配符在前面
- 查询使用OR

redis

  • 缓存雪崩

    缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

    解决方案:将缓存失效的时间分隔开

  • 缓存击穿

    缓存失效的时候大量请求发送过来

    解决方案:用互斥锁 先判断是否失效

    ​ 失效就先重新设置缓存 在查询

  • 缓存穿透

    访问一个不存在的数据

    解决方案:先做一个预判断

操作系统

Posted on 2021-02-27 | Edited on 2021-03-03 | In 面试

进程和线程

​

  • 进程的各个状态

    • 就绪等待被调度

    • 运行 正在执行中

    • 阻塞;缺少需要的资源 等待中

      只有就绪态和运行态可以相互转换,其它的都是单向转换。就绪状态的进程通过调度算法从而获得

  • 线程的各个状态之间的切换

    • 就绪 :进程处于准备好的状态 得到CPU 就可以运行
    • 执行:进程获得cpu 执行
    • 阻塞:正在执行的进程由于发生某事件 暂时无法继续执行
  • 进程和线程

    • 进程: 进程是系统进行资源分配和调度的一个独立单位
    • 线程:是CPU分配和调度的基本单位
  • 进程和线程的关系

    • 一个进程可以拥有多个线程
  • 进程和线程的区别

    • 进程有自己的独立地址空间 线程没有
    • 进程是资源分配的最小单位线程是CPU分配的最小单位
    • 线程通信更方便:
      • 比如同一进程下线程共享数据(全局变量 静态变量)
  • 进程切换代价高

    • 进程切换
      • 需要切换目录地址空间
      • 切换内核栈 硬件上下文
  • 进程调度

    • 非抢占式调度 抢占式调度
    • 调度算法
      • 先进先出,最短作业优先
      • 优先权调度算法
      • 轮转调度算法
      • 多级队列调度
  • 一个程序从开始到结束的过程

    • 预处理 :头文件包含 宏替换
    • 编译:将预处理的文件转换成汇编语言
    • 汇编:将汇编代码转成二进制文件
    • 链接:链接目标生成可执行文件

程序和进程

​ 程序是永久的,进程是暂时的,程序是在数据集上的一次执行

​ 程序是静态的观念,进程是动态的观念

​ 进程具有并发性,而程序没有

​ 进程和程序不是一一对应的,一个程序可以拥有多个进程。

​ 程序有一定的生命周期

了解哪些寄存器

通用寄存器 标志寄存器 段寄存器

进程通信的方式

1. 管道通信 :

  • 命名管道:在内核申请一块固定大小的缓冲区 。程序拥有读写的权利

  • 匿名管道:

    2. 消息队列:

  • 在内核中创建一个队列,队列存储的元素是一个个数据报,不同进程通过句柄去访问这个队列

    3. 信号量:

  • 主要是PV操作

    4. 共享内存:

  • 主要是将一块物理地址映射到不同的进程虚拟地址空间中,实现不同进程堆同一志愿的共享

    5. 套接字( socket ) :

  • 套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。 比如QQ 聊天

死锁的四个条件

​ 互斥 不可剥夺 循环等待 请求和保持

​ 当系统出于安全状态时一定不会进入死锁

​ 当系统处于不安全状态时不一定会死锁

进程调度算法:

​ 先来先服务

​ 短作业优先

​ 时间片轮转调度

高响应比优先

优先权调度算法

多级队列调度算法

内存管理的方式:

段页式存储

​ ① 随机算法:用软件或硬件随机数产生器确定替换的页面
  ② 先进先出:先调入主存的页面先替换
  ③ 近期最少使用算法(LRU,Least Recently Used):替换最长时间不用的页面
  ④ 最优算法:替换最长时间以后才使用的页面。这是理想化的算法,只能作为衡量其他各种算法优劣的标准。

IO 控制的方式:

​ 有轮询 中断 DMA

外中断和异常有什么区别?

外中断是指由 CPU 执行指令以外的事件引起,如 I/O 完成中断,表示设备输入/输出处理已经完成,处理器能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等。

而异常时由 CPU 执行指令的内部事件引起,如非法操作码、地址越界、算术溢出等。

磁盘调度算法

​ 先来先服务

​ 最短寻道优先

​ 电梯算法

动态分区分配算法有哪几种?可以分别说说吗?

1、首次适应算法

算法思想:每次都从低地址开始查找,找到第–个能满足大小的空闲分区。

如何实现:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链( 或空闲分[表),找到大小能满足要求的第-一个空闲分区。

2、最佳适应算法

算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。

如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第-一个空闲分区。

3、最坏适应算法

又称最大适应算法(Largest Fit)

算法思想:为了解决最佳适应算法的问题—即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。

如何实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第-一个空闲分区。

4、邻近适应算法

算法思想:首次适应算法每次都从链头开始查找的。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。

如何实现:空闲分区以地址递增的顺序排列(可排成-一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

​

程序的编译过程

  1. 预编译 主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下
1
2
3
1. 处理所有的预处理命令
2. 处理 define 命令 将内容替换到对应的位置
3. 删除注释 添加行号和文件标识 ()便于调试信息时能够显示行号
  1. 编译 进行语法语义分析生成 汇编代码 .i 文件

  2. 汇编: 将汇编代码转化成机器码

  3. 链接:将不同目标文件链接转化成一个可执行文件

操作系统在对内存进行管理的时候需要做些什么?

  • 操作系统负责内存空间的分配与回收。
  • 操作系统需要提供某种技术从逻辑上对内存空间进行扩充。
  • 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换。
  • 操作系统需要提供内存保护功能。保证各进程在各自存储空间内运行,互不干扰

五大IO 模型

  • 阻塞Io

  • 非阻塞IO 不断询问 询问中间 可以做其他的事情

  • 信号驱动:

    用户事先在内核注册一个信号处理函数,管道和内核进行交互,当管道中的某个请求需要的数据处理好之后,进程再把对应的数据拷贝到用户空间中。

  • IO 复用模型 NIO Channel , Selector,Buffer

    多个进程的IO 可以注册到同一个管道上,这个管道会统一和内核进行交互,当管道中数据准备好之后,进程再把对应的数据拷贝到用户空间。

  • 异步IO

    应用进程 把IO请求传递给内核后,完全由内核去操作文件拷贝,内核完成相关操作后,会发信号告诉本次应用进程本次IO 已经完成。

​

​

docker 常用命令

Posted on 2021-02-27 | In 其他
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

• 容器有三种状态 暂停 运行 停止
• docker exec -it eb14fc75272f bash
• docker exec -i re bash -c "ls als"
• -t 表示进入容器内执行命令
• docker rm e00b8e3e3e2e 移除镜像
• docker run --name helloworld hello-world
• 移除镜像 docker rmi hello-world
• 已打包的镜像 交父镜像 父镜像移除子镜像必须先移除父镜像
• docker 打包项目镜像
• 导入JDK 环境
• 新疆Dockerfile 文件
• From ubuntu:20.04
• COPY jdk1.8.0_271 /test
• COPY helloworld.jar /test
• docker build -t demo:1.0 .
• docker cp 拷贝镜像到宿主机 反过来可以
• docker cp helloworld.jar demo:/test
• h

hashmap详解

Posted on 2021-02-25 | Edited on 2021-03-15 | In 面试
  1. hashmap特性

    hashmap 可以实现快速存取 key 允许为null

    非同步 线程不安全

    底层时hash表

    负载因子是0.75

  2. hashmap 的底层实现原理

    底层时数组加链表 put get存取对象 当执行put 方法时 , 先对键值计算hashcode()得到它在bucket数组的位置。获取对象时,先得到bucket的位置 在调用equals 找到需要的值。

  1. put 方法的流程

    1. 计算机hashcode
    2. 判断hash表是否为空
    3. 发生碰撞放到散列表里去
    4. hashcode 值相同 三种情况
      1. equals 判断是否有相同 相同就替换
      2. 红黑树就调用红黑树的插入方法
      3. 链表就在尾部插入 如果插入链表个数为8 就转变为红黑树
    5. 如果满了就扩容。
  1. hashmap 什么时候需要扩容

    1. 通过判断数组容量是否大于0 判断数组是否初始化过
    2. 没有初始化
      1. 是否初始化默认大小
        1. 是否初始化容量
        2. 扩容两倍将元素重新运算复制到新的散列表中
  1. 5.谈一下hashMap中get是如何实现的?

    对key的hashCode进行hashing,与运算计算下标获取bucket位置,如果在桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找,如果有hash冲突,则利用equals方法去遍历链表查找节点。

  2. hashmap 和 hashtable 的区别

    1. 相同点

      1. 都是key-value 存储

        1. HashMap允许Key-value为null,hashTable不允许;
          1. hashMap没有考虑同步,是线程不安全的。hashTable是线程安全的,给api套上了一层synchronized修饰;
        2. hashmap 的初始容量是16 hashtable 的初始容量是 11 (2*n+1)
        3. hashmap 自定义的hash算法 hashtable 没有自定义hash算法
  1. loadfactor

    1. 表示hash 表的拥挤程度

​

代理模式

Posted on 2021-02-25 | In 设计模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public interface IGamePlayer {
public void killBoss();
public void upGrade();
}


public class GamePlayer implements IGamePlayer{

private String name;

public GamePlayer() {
}

public GamePlayer(String name) {
this.name = name;
}

@Override
public void killBoss() {
System.out.println("打怪");
}

@Override
public void upGrade() {
System.out.println("升级");
}


}



public class GamePlayerProxy implements IGamePlayer{
private IGamePlayer player = null;
public GamePlayerProxy(IGamePlayer player){
this.player= player;
}

private void log(){
System.out.println("打怪 时间 " + new Date().toString());
}

@Override
public void killBoss() {
System.out.println("打怪前");
player.killBoss();
System.out.println("打怪后");
}

@Override
public void upGrade() {

}
}


public class Client {

public static void main(String[] args) {
GamePlayer gamePlayer = new GamePlayer("李逍遥");
GamePlayerProxy gamePlayerProxy = new GamePlayerProxy(gamePlayer);
gamePlayerProxy.killBoss();
}
}

抽象工厂模式

Posted on 2021-02-25 | In 设计模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public abstract class Article {
public abstract void produce();
}
public abstract class Video {
public abstract void produce();
}

//实现类
public class JavaArticle extends Article{

@Override
public void produce() {
System.out.println("生产文章");
}
}
public class JavaVideo extends Video{

@Override
public void produce() {
System.out.println("生成video");
}
}

课程
public interface CourseFactory {
Video getVideo();
Article getArtcle();
}

public class MyFactory implements CourseFactory{

@Override
public Video getVideo() {
return new JavaVideo();
}

@Override
public Article getArtcle() {
return new JavaArticle();
}
}


//主类
public class Client {
public static void main(String[] args) {
MyFactory myFactory = new MyFactory();
Article artcle = myFactory.getArtcle();
Video video = myFactory.getVideo();
artcle.produce();
video.produce();
}
}

招银云创二面凉经

Posted on 2021-02-24 | In 面试
  1. 自我介绍

    • 巴拉巴拉
  2. 介绍提到大学开发过项目

    针对项目 问的问题

    1. 问我用过那些注解
    2. 谈谈@Controller 和@Service 的区别
    3. controller service dao 分别写什么代码
    4. 原来用ssm 现在 为什么用springboot
    5. springboot 为什么可以简化配置
    6. Mybaties 执行器
    7. Mybaties 用过那些标签
    8. mybaties 可以重载?
  3. JUC

    1. 谈谈JUC 的理解
    2. synchronized 如何实现同步
  4. 集合框架

    1. 谈谈你对hashmap 的理解
    2. hashmap 和hashtable 的区别
    3. hashmap 为什么是线程安全额
    4. hash map 的key和value 可以为空
    5. 为什么不能为空

总结

面试时间是半小时 面试的是公司的架构师,问题都很开放先谈理解 根据你说的再问。

责任链模式

Posted on 2021-02-23 | In 设计模式

z责任链模式:

  1. 新建请求
  2. 新建各级主管
  3. 新建各级主管建立链表
  4. 初级主管开始 判断能否处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
public class AbstractLeaveHandler {
/**直接主管审批处理的请假天数*/
protected int MIN = 1;
/**部门经理处理的请假天数*/
protected int MIDDLE = 3;
/**总经理处理的请假天数*/
protected int MAX = 30;

/**领导名称*/
protected String handlerName;

/**下一个处理节点(即更高级别的领导)*/
protected AbstractLeaveHandler nextHandler;

/**设置下一节点*/
protected void setNextHandler(AbstractLeaveHandler handler){
this.nextHandler = handler;
}

/**处理请假的请求,子类实现*/
protected void handlerRequest(LeaveRequest request){

}
}



//直接主管
public class DirectLeaderLeaveHandler extends AbstractLeaveHandler{
public DirectLeaderLeaveHandler(String name) {
this.handlerName = name;
}

@Override
protected void handlerRequest(LeaveRequest request) {
if(request.getLeaveDays() <= this.MIN){
System.out.println("直接主管:" + handlerName + ",已经处理;流程结束。");
return;
}

if(null != this.nextHandler){
this.nextHandler.handlerRequest(request);
}else{
System.out.println("审批拒绝!");
}

}
}

//部门经理
public class DeptManagerLeaveHandler extends AbstractLeaveHandler{
public DeptManagerLeaveHandler(String name) {
this.handlerName = name;
}

@Override
protected void handlerRequest(LeaveRequest request) {
if(request.getLeaveDays() >this.MIN && request.getLeaveDays() <= this.MIDDLE){
System.out.println("部门经理:" + handlerName + ",已经处理;流程结束。");
return;
}

if(null != this.nextHandler){
this.nextHandler.handlerRequest(request);
}else{
System.out.println("审批拒绝!");
}
}
}

//总经理
public class GManagerLeaveHandler extends AbstractLeaveHandler{
public GManagerLeaveHandler(String name) {
this.handlerName = name;
}

@Override
protected void handlerRequest(LeaveRequest request) {
if(request.getLeaveDays() > this.MIDDLE && request.getLeaveDays() <= this.MAX){
System.out.println("总经理:" + handlerName + ",已经处理;流程结束。");
return;
}

if(null != this.nextHandler){
this.nextHandler.handlerRequest(request);
}else{
System.out.println("审批拒绝!");
}
}

}

//请求
public class LeaveRequest {

//请求天数和名字
private int leaveDays;
private String name;
}

//客户端
public class ResponsibilityTest {
public static void main(String[] args) {
LeaveRequest request = LeaveRequest.builder().leaveDays(5).name("小明").build();


AbstractLeaveHandler directLeaderLeaveHandler = new DirectLeaderLeaveHandler("县令");
DeptManagerLeaveHandler deptManagerLeaveHandler = new DeptManagerLeaveHandler("知府");
GManagerLeaveHandler gManagerLeaveHandler = new GManagerLeaveHandler("京兆尹");

directLeaderLeaveHandler.setNextHandler(deptManagerLeaveHandler);
deptManagerLeaveHandler.setNextHandler(gManagerLeaveHandler);

directLeaderLeaveHandler.handlerRequest(request);


}
}

策略模式

Posted on 2021-02-23 | In 设计模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//策略类
public abstract class Strategy {
public abstract void algorithmInterface();
}


//策略A 和 策略B
public class StrategyA extends Strategy{

@Override
public void algorithmInterface() {
System.out.println("算法A 的思想");
}
}


// 策略B
public class StrategyB extends Strategy{

@Override
public void algorithmInterface() {
System.out.println("算法B 的思想");
}
}


// 策略的执行对象
public class Context {

Strategy strategy;

public Context(Strategy strategy){
this.strategy = strategy;
}

public void contextInterFace(){
strategy.algorithmInterface();
}
}

//客户端
public class Client {


public static void main(String[] args) {
Context context;
context = new Context(new StrategyA());
context.contextInterFace();
context = new Context(new StrategyB());
context.contextInterFace();
}

}

AQS实现锁的框架

Posted on 2021-02-17

s

1234
Author

Author

40 posts
10 categories
14 tags
GitHub 简书
Links
  • csdn
  • github
© 2021 认识世界 认识你自己