河狸家-2021-4-13
# 面试过程
先自我介绍
先聊项目
谈谈你项目里负责的模块
开始追着项目模块细问
谈到多线程更新缓存数据时,被问到会不会有并发的问题,怎么解决(主要是redis更新操作不是原子性的,可能存在并发操作)
加synchronized在方法上,或者如果只是覆盖的话setnx命令保证原子性
开始问简历上的东西
设计模式
观察者模式
自己讲了监听者模式,也没讲明白
(可以讲代理模式)
Linux
怎么查日志 tail -f -n 数量 查询最近行数的日志
查关键字 加 | grep
查询关键字时忽略大小写(不会) grep -i 文件名
查询日志行数(不会)nl 文件名
有没有查过系统参数(不会)
df -h 查看磁盘占用的空间
cloud
说下你对注册中心的理解(服务的注册流程,发现流程,自我保护机制)
sql优化的经历
说了下 explain 的使用 type keys 字段的解释,
说了下 工作中发现函数使查询速度减慢,索引的添加,最左匹配原则和关联字段加索引
sql优化补充
谈谈自己是怎么学习的
脑子抽风说了自己最近在看jvm的书,这不是挖坑吗,
然后把类加载机制的那五个步骤说了一边
其中说到验证时,被问到只有class文件格式被验证吗?
类加载机制补充
又被问工作的时候怎么学习的,学到了什么 ?
就把自己学gitlab版的ci ,docker 编写dockerfile 说了下,但是面试官没有继续问下去
面试官说有什么想问的吗?
- 做什么业务
- 技术栈用的那些
总结:
总的来说面试很失败,被面试官稍微再问下,就不会了,看来学习的深度不够,还是要加强学习。
# 知识补充
# linux命令补充
grep使用
Regexp selection and interpretation: -E, --extended-regexp PATTERN is an extended regular expression (ERE) -F, --fixed-strings PATTERN is a set of newline-separated fixed strings -G, --basic-regexp PATTERN is a basic regular expression (BRE) -P, --perl-regexp PATTERN is a Perl regular expression -e, --regexp=PATTERN use PATTERN for matching -f, --file=FILE obtain PATTERN from FILE -i, --ignore-case ignore case distinctions -w, --word-regexp force PATTERN to match only whole words -x, --line-regexp force PATTERN to match only whole lines -z, --null-data a data line ends in 0 byte, not newline Miscellaneous: -s, --no-messages suppress error messages -v, --invert-match select non-matching lines -V, --version display version information and exit --help display this help text and exit Output control: -m, --max-count=NUM stop after NUM matches -b, --byte-offset print the byte offset with output lines -n, --line-number print line number with output lines --line-buffered flush output on every line -H, --with-filename print the file name for each match -h, --no-filename suppress the file name prefix on output --label=LABEL use LABEL as the standard input file name prefix -o, --only-matching show only the part of a line matching PATTERN -q, --quiet, --silent suppress all normal output --binary-files=TYPE assume that binary files are TYPE; TYPE is 'binary', 'text', or 'without-match' -a, --text equivalent to --binary-files=text -I equivalent to --binary-files=without-match -d, --directories=ACTION how to handle directories; ACTION is 'read', 'recurse', or 'skip' -D, --devices=ACTION how to handle devices, FIFOs and sockets; ACTION is 'read' or 'skip' -r, --recursive like --directories=recurse -R, --dereference-recursive likewise, but follow all symlinks --include=FILE_PATTERN search only files that match FILE_PATTERN --exclude=FILE_PATTERN skip files and directories matching FILE_PATTERN --exclude-from=FILE skip files matching any file pattern from FILE --exclude-dir=PATTERN directories that match PATTERN will be skipped. -L, --files-without-match print only names of FILEs containing no match -l, --files-with-matches print only names of FILEs containing matches -c, --count print only a count of matching lines per FILE -T, --initial-tab make tabs line up (if needed) -Z, --null print 0 byte after FILE name Context control: -B, --before-context=NUM print NUM lines of leading context -A, --after-context=NUM print NUM lines of trailing context -C, --context=NUM print NUM lines of output context -NUM same as --context=NUM --group-separator=SEP use SEP as a group separator --no-group-separator use empty string as a group separator --color[=WHEN], --colour[=WHEN] use markers to highlight the matching strings; WHEN is 'always', 'never', or 'auto' -U, --binary do not strip CR characters at EOL (MSDOS/Windows) -u, --unix-byte-offsets report offsets as if CRs were not there (MSDOS/Windows)
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查询系统命令
uname -a # 查看内核/操作系统/CPU信息的linux系统信息 head -n l /etc/issue # 查看操作系统版本 cat /proc/cpuinfo # 查看CPU信息 hostname # 查看计算机名的linux系统信息命令 lspci -tv # 列出所有PCI设备 lsusb -tv # 列出所有USB设备的linux系统信息命令 lsmod # 列出加载的内核模块 env # 查看环境变量资源 free -m # 查看内存使用量和交换区使用量 df -h # 查看各分区使用情况 du -sh # 查看指定目录的大小 grep MemTotal /proc/meminfo # 查看内存总量 grep MemFree /proc/meminfo # 查看空闲内存量 uptime # 查看系统运行时间、用户数、负载 cat /proc/loadavg # 查看系统负载磁盘和分区 mount | column -t # 查看挂接的分区状态 fdisk -l # 查看所有分区 swapon -s # 查看所有交换分区 hdparm -i /dev/hda # 查看磁盘参数(仅适用于IDE设备) dmesg | grep IDE # 查看启动时IDE设备检测状况网络 ifconfig # 查看所有网络接口的属性 iptables -L # 查看防火墙设置 route -n # 查看路由表 netstat -lntp # 查看所有监听端口 netstat -antp # 查看所有已经建立的连接 netstat -s # 查看网络统计信息进程 ps -ef # 查看所有进程 top # 实时显示进程状态用户 w # 查看活动用户 id # 查看指定用户信息 last # 查看用户登录日志 cut -d: -f1 /etc/passwd # 查看系统所有用户 cut -d: -f1 /etc/group # 查看系统所有组 crontab -l # 查看当前用户的计划任务服务 chkconfig –list # 列出所有系统服务 chkconfig –list | grep on # 列出所有启动的系统服务程序 rpm -qa # 查看所有安装的软件包 cat /proc/cpuinfo :查看CPU相关参数的linux系统命令 cat /proc/partitions :查看linux硬盘和分区信息的系统信息命令 cat /proc/meminfo :查看linux系统内存信息的linux系统命令 cat /proc/version :查看版本,类似uname -r cat /proc/ioports :查看设备io端口 cat /proc/interrupts :查看中断 cat /proc/pci :查看pci设备的信息 cat /proc/swaps :查看所有swap分区的信息
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
# sql优化补充
# explain
如果是mysql的话,我们可以了解下 使用 如何查看执行计划
-- 查看SQL是否使用索引,前面加上explain即可
explain select * from emp where name = 'Jefabc';
-- expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
2
3
4
一、 id
SELECT识别符。这是SELECT的查询序列号
我的理解是SQL执行的顺序的标识,SQL从大到小的执行
id相同时,执行顺序由上至下
如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
二、select_type
查询中每个select子句的类型
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
(2) PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
(3) UNION(UNION中的第二个或后面的SELECT语句)
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
(5) UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)
(6) SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)
(8) DERIVED(派生表的SELECT, FROM子句的子查询)
(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
三、table
显示这一步所访问数据库中表名称(显示这一行的数据是关于哪张表的),有时不是真实的表名字,可能是简称,例如上面的e,d,也可能是第几步执行的结果的简称
四、type
对表访问方式,表示MySQL在表中找到所需行的方式,又称“访问类型”。
常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)
ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
index: Full Index Scan,index与ALL区别为index类型只遍历索引树
range:只检索给定范围的行,使用一个索引来选择行
ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
五、possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)
该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。 如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询
六、Key
key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中
如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
七、key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
不损失精确性的情况下,长度越短越好
八、ref
列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
九、rows
估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
十、Extra
该列包含MySQL解决查询的详细信息,有以下几种情况:
Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by
Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”
sing join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
Impossible where:这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。
Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
No tables used:Query语句中使用from dual 或不含任何from子句
# sql优化
① SQL优化
避免 SELECT *,只查询需要的字段。
小表驱动大表,即小的数据集驱动大的数据集:
当B表的数据集比A表小时,用in优化 exist两表执行顺序是先查B表再查A表查询语句:SELECT * FROM tb_dept WHERE id in (SELECT id FROM tb_dept) ;
当A表的数据集比B表小时,用exist优化in ,两表执行顺序是先查A表,再查B表,查询语句:SELECT * FROM A WHERE EXISTS (SELECT id FROM B WHERE A.id = B.ID) ;
尽量使用连接代替子查询,因为使用 join 时,MySQL 不会在内存中创建临时表。
2
3
4
5
② 优化索引的使用
尽量使用主键查询,而非其他索引,因为主键查询不会触发回表查询。
不做列运算,把计算都放入各个业务系统实现
查询语句尽可能简单,大语句拆小语句,减少锁时间
or 查询改写成 union 查询
不用函数和触发器
避免 %xx 查询,可以使用:select * from t where reverse(f) like reverse('%abc');
少用 join 查询
使用同类型比较,比如 '123' 和 '123'、123 和 123
尽量避免在 where 子句中使用 != 或者 <> 操作符,查询引用会放弃索引而进行全表扫描
列表数据使用分页查询,每页数据量不要太大
避免在索引列上使用 is null 和 is not null
2
3
4
5
6
7
8
9
10
11
③ 表结构设计优化
使用可以存下数据最小的数据类型。
尽量使用 tinyint、smallint、mediumint 作为整数类型而非 int。
尽可能使用 not null 定义字段,因为 null 占用 4 字节空间。数字可以默认 0 ,字符串默认 “”
尽量少用 text 类型,非用不可时最好独立出一张表。
尽量使用 timestamp,而非 datetime。
单表不要有太多字段,建议在 20 个字段以内。
2
3
4
5
6
# 类加载机制补充
# 类加载时机
遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始
化,则需要先触发其初始化阶段。
使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需
要先触发其初始化
当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先
初始化这个主类。
当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解
析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句
柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有
这个接口的实现类发生了初始化,那该接口要在其之前被初始化。
对于这六种会触发类型进行初始化的场景,《Java虚拟机规范》中使用了一个非常强烈的限定语
——“有且只有”,这六种场景中的行为称为对一个类型进行主动引用。除此之外,所有引用类型的方
式都不会触发初始化,称为被动引用
# 类加载机制主要五个阶段
# 加载
“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段,希望读者没有混淆
这两个看起来很相似的名词。在加载阶段,Java虚拟机需要完成以下三件事情:
1)通过一个类的全限定名来获取定义此类的二进制字节流。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入
口。
总的来说,虚拟机拿到class文件(或者是其他形式)转化为类对象存放在方法区中。
# 验证
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
# 准备
准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初
始值的阶段。
# 解析
解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。
·符号引用(Symbolic References):符号引用以一组符号来描述所引用的目标,符号可以是任何
形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引
用的目标并不一定是已经加载到虚拟机内存当中的内容。各种虚拟机实现的内存布局可以各不相同,
但是它们能接受的符号引用必须都是一致的,因为符号引用的字面量形式明确定义在《Java虚拟机规
范》的Class文件格式中。
·直接引用(Direct References):直接引用是可以直接指向目标的指针、相对偏移量或者是一个能
间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局直接相关的,同一个符号引用在不同虚
拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在虚拟机
的内存中存在。
# 初始化
初始化阶段就是执行类构造器方法的过程
方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的
语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的,静态语句块中只能访问
到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访
问