51. 测试题(答案详析)

文章目录

测试题20

1. redis操作string类型常用命令(至少5个)?
  1. set :用于给指定的key设置value,支持设置已存在的key
  2. get:用于取指定key的value
  3. setnx:用于给指定的key设置value,如果key已经存在则返回0。nx代表:not exist
  4. setex:用于给指定的key设置value,并且需要指定该key的有效时间。 10秒后则返回为空
  5. setrange:给指定的key的值重新覆盖内容,从4指定位置
  6. mset:批量设置key对应的value值,以下设置username、age、sex 分别对应 zhu、1、0; eg: mset username zhu age 1 sex 0
  7. msetnx:批量设置key对应的value值,如果key已存在则返回0;eg:msetnx username zhu age 10 sex 0
  8. getset:给指定key设置新值,并且返回之前原始数据。
  9. getrange:返回一个字符串的子字符串,相当于字符串截取,下标0是起始位置,下标3是结尾位置;eg:getrange username 0 3
  10. mget:批量获取key对应的value,按顺序展示
  11. incr:将指定key中存储的数字值增一,必须是数字类型,否则会返回错误信息
  12. decr:将指定key中存储的数字值减一,必须是数字类型,否则会返回错误信息
  13. decrby:将指定key中存储的数字指定减少多少,以下指定减少10
  14. append:给指定的key中的值追加字符串
  15. strlen:返回指定key中value的长度
#1.  添加值
set key value

#2. 取值
get key

#3. 批量操作
mset key value [key value...]
mget key [key...]

#4. 自增命令(自增1)
incr key 

#5. 自减命令(自减1)
decr key

#6. 自增或自减指定数量
incrby key increment
decrby key increment

#7. 设置值的同时,指定生存时间(每次向Redis中添加数据时,尽量都设置上生存时间)
setex key second value

#8. 设置值,如果当前key不存在的话(如果这个key存在,什么事都不做,如果这个key不存在,和set命令一样)
setnx key value

#9. 在key对应的value后,追加内容
append key value

#10. 查看value字符串的长度
strlen key

#11. TTL 查看变量的生存时间
 TTL name
(integer) -1 #表示没有设置生存时间
(integer) -2 #变量已经消失了

#12. EXPIRE 设置变量的生存时间
127.0.0.1:6379> expire name 20 #设置name变量存活20秒钟

#13. 综合 name不存在时,设置name的值为zhangsan,并且有效期为100秒
# ex设置有效期
# nx不存在则设置变量
# xx存在则设置变量
set name zhangsan ex 100 nx 

#13.DEL
127.0.0.1:6379> DEL name #将key为name的进行删除
2. redis操作hash类型常用命令(至少5个)?
  1. hset 命令:hset 将hash表中key 的 field域设置为值value。如果key值不存在,操作成功后返回1,如果key值已经存在,则覆盖原来的值,成功后返回0。eg:hset user name ‘zhu’ # 设置值为zhu

  2. hget 命令:hget 返回hash表中指定key的field的值。eg:hget user name

  3. hsetnx 命令:hsetnx 当且仅当filed域不存在时,设置值为value。如果该域不存在,返回1,如果该域已经存在,则不会执行操作,且返回0。

    redis 127.0.0.1:6379> hget user name
    "zhu"
    redis 127.0.0.1:6379> hsetnx user name 'zzz'
    (integer) 0                                          # 将name域的值设置为zzz时操作失败,因为name域已经存在
    redis 127.0.0.1:6379> hsetnx user age  12<span style="white-space:pre">	</span>     # 将age域的值设置为12,操作成功,应为age域不存在
    (integer) 1
    redis 127.0.0.1:6379> hget user name                 # 取出name的值,并没有被修改
    "zhangsna"
    redis 127.0.0.1:6379> hget user age
    "12"
    redis 127.0.0.1:6379>
    
  4. hmset 命令:hmset [ …] 同时将多个“域-值”对存储在key键中,如果key不存在会自动创建,如果field已经存在,则会覆盖原来的值。操作成功后返回值OK。eg:hmset product name ‘computer’ price ‘3200’ size ‘14inch’ OK

  5. hmget 命令:hmget […] 返回hash表中key的一个或者多个域值。如果给定的域名称在此hash表中不存在,则返回nil。

  6. hgetall 命令:hgetall 返回hash表中key的所有域的值。

  7. hlen 命令:hlen 返回hash表中key中所有域的总数。当key值不存在时,返回0.

  8. hexists 命令:hexists 查看hash表中,给定key的域field是否存在。如果存在,则返回1,如果field不存在或者是key也不存在,返回0。

#1. 存储数据
hset key field value

#2. 获取数据
hget key field

#3. 批量操作
hmset key field value [field value ...]
hmget key field [field ...]

#4. 自增(指定自增的值)
hincrby key field increment

#5. 设置值(如果key-field不存在,那么就正常添加,如果存在,什么事都不做)
hsetnx key field value

#6. 检查field是否存在
hexists key field 

#7. 删除key对应的field,可以删除多个
hdel key field [field ...]

#8. 获取当前hash结构中的全部field和value
hgetall key

#9. 获取当前hash结构中的全部field
hkeys key

#10. 获取当前hash结构中的全部value
hvals key

#11. 获取当前hash结构中field的数量
hlen key
3. redis操作list类型常用命令(至少5个)?
#1. 存储数据(从左侧插入数据,从右侧插入数据)
lpush key value [value ...]
rpush key value [value ...]

#2. 存储数据(如果key不存在,什么事都不做,如果key存在,但是不是list结构,什么都不做)
lpushx key value
rpushx key value

#3. 修改数据(在存储数据时,指定好你的索引位置,覆盖之前索引位置的数据,index超出整个列表的长度,也会失败)
lset key index value

#4. 弹栈方式获取数据(左侧弹出数据,从右侧弹出数据)
lpop key
rpop key

#5. 获取指定索引范围的数据(start从0开始,stop输入-1,代表最后一个,-2代表倒数第二个)
lrange key start stop

#6. 获取指定索引位置的数据
lindex key index

#7. 获取整个列表的长度
llen key

#8. 删除列表中的数据(他是删除当前列表中的count个value值,count > 0从左侧向右侧删除,count < 0从右侧向左侧删除,count == 0删除列表中全部的value)
lrem key count value

#9. 保留列表中的数据(保留你指定索引范围内的数据,超过整个索引范围被移除掉)
ltrim key start stop

#10. 将一个列表中最后的一个数据,插入到另外一个列表的头部位置
rpoplpush list1 list2
4. redis操作set类型常用命令(至少5个)?
#1. 存储数据
sadd key member [member ...]

#2. 获取数据(获取全部数据)
smembers key

#3. 随机获取一个数据(获取的同时,移除数据,count默认为1,代表弹出数据的数量)
spop key [count]

#4. 交集(取多个set集合交集)
sinter set1 set2 ...

#5. 并集(获取全部集合中的数据)
sunion set1 set2 ...

#6. 差集(获取多个集合中不一样的数据)
sdiff set1 set2 ...

# 7. 删除数据
srem key member [member ...]

# 8. 查看当前的set集合中是否包含这个值
sismember key member
5. redis操作zset(Sorted Set)类型常用命令(至少5个)?
#1. 添加数据(score必须是数值。member不允许重复的。)
zadd key score member [score member ...]

#2. 修改member的分数(如果member是存在于key中的,正常增加分数,如果memeber不存在,这个命令就相当于zadd)
zincrby key increment member

#3. 查看指定的member的分数
zscore key member

#4. 获取zset中数据的数量
zcard key

#5. 根据score的范围查询member数量
zcount key min max

#6. 删除zset中的成员
zrem key member [member...]

#7. 根据分数从小到大排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrange key start stop [withscores]

#8. 根据分数从大到小排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrevrange key start stop [withscores]

#9. 根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样,如果不希望等于min或者max的值被查询出来可以采用 ‘(分数’ 相当于 < 但是不等于的方式,最大值和最小值使用+inf和-inf来标识)
zrangebyscore key min max [withscores] [limit offset count]

#10. 根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样)
zrangebyscore key max min [withscores] [limit offset count]

redis特点:
1. 开源
2. 基于内存的数据存储结构
3. 可以作为数据库或缓存的数据中间件
4. 支持丰富的数据类型
5. 支持持久化
6. 高性能(单线程的)的数据库
7. 支持集群、支持哨兵模式

6. maven中怎么解决jar包冲突,怎么保证jar包的版一致?
  1. 最短路径原则
  2. 声明优先原则
  3. 依赖排除
7. session共享有什么方案,具体怎么实现?
  1. nginx基于ip_hash负载均衡。只需要更改nginx.conf配置文件。添加ip_hash即可。缺点:
    1. 由于ip_hash分配tomcat的时候用的是除法,所以新添加一台服务器会导致分配不到原来程序上,session会丢失。
    2. 2.同一个公网ip访问时,ngnix会分到tomcat1上面,后面所有的同一公网下的内网路由访问都会分配到tomcat1上,还是会造成单台设备服务压力大3.单台服务器挂了后会导致session丢失。需要用户重新登录。
  1. 服务器session复制:操作:修改tomcat配置文件

  2. session统一缓存:

    配置步骤:修改应用的配置文件

    1. 增加redis client和spring session的依赖;
    2. 修改web.xml,增加filter:springSessionRFilter;
    3. 修改spring配置文件,在容器中注入spring session和redis相关的bean;
  1. redis+tomcat实现session共享
8. 介绍一下索引,索引有什么优缺点。

导读:索引是在存储引擎中实现的,也就是说不同的存储引擎,会使用不同的索引。MyISAM和InnoDB存储引擎:只支持BTREE索引,也就是说默认使用BTREE,不能够更换。MEMORY/HEAP存储引擎:支持HASH和BTREE索引。

mysql的索引我们分为三大类来讲单列索引(普通索引,唯一索引,主键索引)、组合索引、全文索引。

一、单列索引:一个索引只包含单个列,但一个表中可以有多个单列索引。 这里不要搞混淆了

1:普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一 点。

2:唯一索引:索引列中的值必须是唯一的,但是允许为空值。

3:主键索引:是一种特殊的唯一索引,不允许有空值。(主键约束,就是一个主键索引)。

主键索引与唯一索引的区别:

\1. 主键是一种约束,唯一索引是一种索引,两者在本质上是不同的。

\2. 主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键。

\3. 唯一性索引列允许空值,而主键列不允许为空值。

\4. 主键索引在创建时,已经默认为非空值+ 唯一索引了。

\5. 一个表最多只能创建一个主键索引,但可以创建多个唯一索引。

\6. 主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等。

\7. 主键可以被其他表引用为外键,而唯一索引不能。

二、组合索引:在表中的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。例如,这里由id、name和age3个字段构成的索引,索引行中就按id/name/age的顺序存放,索引可以索引下面字段组合(id,name,age)、(id,name)或者(id)。如果要查询的字段不构成索引最左面的前缀,那么就不会是用索引,比如,age或者(name,age)组合就不会使用索引查询。

三、全文索引:全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用全文索引,介绍了要求,说说什么是全文索引,就是在一堆文字中,通过其中的某个关键字等,就能找到该字段所属的记录行,比如有"你是个大煞笔,二货 …" 通过大煞笔,可能就可以找到该条记录。这里说的是可能,因为全文索引的使用涉及了很多细节,我们只需要知道这个大概意思。一般开发中,不贵用到全文索引,因为其占用很大的物理空间和降低了记录修改性,故较为少用。

创建索引的语句:

1:直接创建索引:

CREATE INDEX index_name ON table(column(length));  创建普通索引
CREATE UNIQUE INDEX indexName ON table(column(length)); 创建唯一索引
CREATE FULLTEXT INDEX index_content ON article(content); 全文索引

2:修改表结构的方式添加索引:

ALTER TABLE table_name ADD INDEX index_name ON (column(length));  创建普通索引
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length)); 创建唯一索引
ALTER TABLE `table` ADD INDEX name_city_age (name,city,age);  组合索引
ALTER TABLE article ADD FULLTEXT index_content(content); 全文索引

3:创建表的时候创建索引:

CREATE TABLE `table` (

    `id` int(11) NOT NULL AUTO_INCREMENT ,

    `title` char(255) CHARACTER NOT NULL ,

    `content` text CHARACTER NULL ,

    `time` int(10) NULL DEFAULT NULL ,

    PRIMARY KEY (`id`),

    INDEX index_name (title(length))

);  普通索引
CREATE TABLE `table` (

    `id` int(11) NOT NULL AUTO_INCREMENT ,

    `title` char(255) CHARACTER NOT NULL ,

    `content` text CHARACTER NULL ,

    `time` int(10) NULL DEFAULT NULL ,

    UNIQUE indexName (title(length))

);  唯一索引
CREATE TABLE `table` (

    `id` int(11) NOT NULL AUTO_INCREMENT ,

    `title` char(255) NOT NULL ,

    PRIMARY KEY (`id`)

);  主键索引
CREATE TABLE `table` (

    `id` int(11) NOT NULL AUTO_INCREMENT ,

    `title` char(255) CHARACTER NOT NULL ,

    `content` text CHARACTER NULL ,

    `time` int(10) NULL DEFAULT NULL ,

    PRIMARY KEY (`id`),

    FULLTEXT (content)

);  全文索引

4:删除索引:

DROP INDEX index_name ON table;

*5:查看索引:*

show index from table_name;

索引的优缺点

1、优点:创建索引可以大大提高系统的性能。
第一、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二、可以大大加快 数据的检索速度,这也是创建索引的最主要的原因。
第三、可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四、在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五、通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

2、缺点

​ 增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?这是因为,增加索引也有许多不利的一个方面:

​ 第一、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

​ 第二、索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么 需要的空间就会更大。

​ 第三、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

*哪些字段适合作为索引(不适合作为索引):*

一般来说,应该在这些列上创建索引,例如:

​ 第一、在经常需要搜索的列上,可以加快搜索的速度;

​ 第二、在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;

​ 第三、在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;

​ 第四、在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;

​ 第五、在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;

​ 第六、在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

*什么样的字段不适合创建索引:*

第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,

并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,

在查询的结果中,结果集的数据行占了表中数据行的很大比 例,即需要在表中搜索的数据行的比例很大。

增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索 引。这是因为,修改性能和检索性能是互相矛盾的。

当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。

因此,当修改性能远远大于检索性能时,不应该创建索引。

9. MySQL中Int(10)和int(11)区别?

宽度不同

int(M) 中的M指示最大显示宽度,最大有效显示宽度是 255,且显示宽度与存储大小或类型包含的值的范围无关。

10. Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?

keys 前缀* 单线程,阻塞
scan 位置
类似于数据库中游标

测试题21

1. @Autowired@Qualifier区别

@Autowired:按照类型
@Qualifier:在类型的基础上按照名称注入

2. Redis是单线程的,但Redis为什么这么快?

内存存储
多路复用

3. 事务在什么情况下回失效。

trycatch
抛出检测异常
MYISAM

4. AOP的原理

动态代理

5. InnoDB存储引擎和MyISAM存储引擎的区别?

MySQL最主要的两种存储引擎是InnoDBMyISAM
InnoDB存储引擎是MySQL的默认使用引擎,它被设计用来处理大量短期事务,一般情况下使用该存储引擎。
MyISAM存储引擎提供了大量的特性,包括全文索引、压缩、空间函数等,但该存储引擎不支持事务和行锁,最致命的缺陷就是崩溃后无法进行恢复。

两者的区别:

MyISAMInnoDB
外键不支持支持
事务不支持支持
航标锁只支持表锁既支持表锁,又支持行锁。杭锁实际上锁的是索引,本行有索引的话使用行锁,没有索引的话就使用表锁
缓存只缓存索引,不缓存真实数据,当查询数据时也需要打开表既缓存索引,又缓存真实数据
关注点一般适合查多写少的业务并发写,需要事务,更大的资源
默认安装
默认使用
自带系统表使用
6. redis用在了项目中的那些地方,是怎么实现的?

记录用户信息

7. AOP用在哪些地方?

事务、日志、权限

8. Spring的缓存

Spring中的cache是为方法做缓存的,spring只是提供了个缓存抽象,具体的实现由的三方提供。

要使用Spring缓存,需要以下三步:

  1. 向Spring配置文件导入context:命名空间

  2. 在Spring配置文件启用缓存,具体是添加 <cache:annotation-driven cache-manager=“缓存管理器ID” />

  3. 配置缓存管理器,不同的缓存实现配置不同,如果是EhCache,需要先配置一个ehcache.xml

一、spring缓存配置的两种方法

Spring的缓存方式有两种,一种是直接缓存在内存中,不算真正的缓存实现。一般不推荐使用。这种内置缓存区,使用SimpleCacheManager类作为缓存管理器,底层直接使用JDK的CurrentMap来实现缓存。

第二种是使用Ehcache作为缓存配置:EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。是一个第三方工具。

9. SQL语句的执行顺序
select distinct 字段 from1  join2 on  条件 where group by having order by limit
执行顺序:
	from ->v1
	join->v2
	on->v3
	where ->v4
	select->v5
	group by ->v6
	having->v7
	order by ->v8
	limit->v9

10. MyBatis中的ResultMap

定义结果类型映射

测试题22

1. redis中set和zset的区别

set:无序的
zset:有序的

2. 什么是缓存穿透、缓存击穿、缓存雪崩、缓存倾斜以及解决的方案有哪些?

缓存穿透:redis没有,数据库也没有【在redis中保存最大ID,保存所有ID】
缓存击穿:热点数据到期,导致大量请求访问数据库【删除热点数据的生存时间】
缓存雪崩:大量数据到期【随机生成有效期】
缓存倾斜:热点数据可能集中到某台节点中【增加服务器节点】

3. Redis内存的淘汰策略有哪些?

在Redis内存已经满的时候,添加了一个新的数据,执行淘汰机制。

  • volatile-lru:在内存不足时,Redis会再设置过了生存时间的key中干掉一个最近最少使用的key。
  • allkeys-lru:在内存不足时,Redis会再全部的key中干掉一个最近最少使用的key。
  • volatile-lfu:在内存不足时,Redis会再设置过了生存时间的key中干掉一个最近最少频次使用的key。
  • allkeys-lfu:在内存不足时,Redis会再全部的key中干掉一个最近最少频次使用的key。
  • volatile-random:在内存不足时,Redis会再设置过了生存时间的key中随机干掉一个。
  • allkeys-random:在内存不足时,Redis会再全部的key中随机干掉一个。
  • volatile-ttl:在内存不足时,Redis会再设置过了生存时间的key中干掉一个剩余生存时间最少的key。
  • noeviction:(默认)在内存不足时,直接报错。

指定淘汰机制的方式:maxmemory-policy 具体策略,设置Redis的最大内存:maxmemory 字节大小

4. Redis集群数据存储原理

hash槽(0~16383)
CRC16(key)%16384

5. Redis支持哪些数据类型?

string/set/list/hash/zset/geo/bit/hyperloglogs

6. 如果你多个系统同时操作(并发)Redis带来的数据问题?

生成订单 -》扣库存 -》发送订单结果
数据不一致问题
1.上锁
2.队列

7. 集群和分布式区别?

分布式:多台服务器做不同事情

集群:多台服务器做相同的事情

Redis集群在保证主从加哨兵的基本功能之外,还能够提升Redis存储数据的能力。

8. Redis 的线程模型?

1)文件事件处理器

redis基于reactor模式开发了网络事件处理器,这个处理器叫做文件事件处理器,file event handler。这个文件事件处理器,是单线程的,redis才叫做单线程的模型,采用IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器来处理这个事件。

如果被监听的socket准备好执行accept、read、write、close等操作的时候,跟操作对应的文件事件就会产生,这个时候文件事件处理器就会调用之前关联好的事件处理器来处理这个事件。

文件事件处理器是单线程模式运行的,但是通过IO多路复用机制监听多个socket,可以实现高性能的网络通信模型,又可以跟内部其他单线程的模块进行对接,保证了redis内部的线程模型的简单性。

文件事件处理器的结构包含4个部分:多个socket,IO多路复用程序,文件事件分派器,事件处理器(命令请求处理器、命令回复处理器、连接应答处理器,等等)。

多个socket可能并发的产生不同的操作,每个操作对应不同的文件事件,但是IO多路复用程序会监听多个socket,但是会将socket放入一个队列中排队,每次从队列中取出一个socket给事件分派器,事件分派器把socket给对应的事件处理器。

然后一个socket的事件处理完之后,IO多路复用程序才会将队列中的下一个socket给事件分派器。文件事件分派器会根据每个socket当前产生的事件,来选择对应的事件处理器来处理。

2 )文件事件

当socket变得可读时(比如客户端对redis执行write操作,或者close操作),或者有新的可以应答的sccket出现时(客户端对redis执行connect操作),socket就会产生一个AE_READABLE事件。

当socket变得可写的时候(客户端对redis执行read操作),socket会产生一个AE_WRITABLE事件。

IO多路复用程序可以同时监听AE_REABLE和AE_WRITABLE两种事件,要是一个socket同时产生了AE_READABLE和AE_WRITABLE两种事件,那么文件事件分派器优先处理AE_REABLE事件,然后才是AE_WRITABLE事件。

3 )文件事件处理器

如果是客户端要连接redis,那么会为socket关联连接应答处理器

如果是客户端要写数据到redis,那么会为socket关联命令请求处理器

如果是客户端要从redis读数据,那么会为socket关联命令回复处理器

4 )客户端与 redis 通信的一次流程

在redis启动初始化的时候,redis会将连接应答处理器跟AE_READABLE事件关联起来,接着如果一个客户端跟redis发起连接,此时会产生一个AE_READABLE事件,然后由连接应答处理器来处理跟客户端建立连接,创建客户端对应的socket,同时将这个socket的AE_READABLE事件跟命令请求处理器关联起来。

当客户端向redis发起请求的时候(不管是读请求还是写请求,都一样),首先就会在socket产生一个AE_READABLE事件,然后由对应的命令请求处理器来处理。这个命令请求处理器就会从socket中读取请求相关数据,然后进行执行和处理。

接着redis这边准备好了给客户端的响应数据之后,就会将socket的AE_WRITABLE事件跟命令回复处理器关联起来,当客户端这边准备好读取响应数据时,就会在socket上产生一个AE_WRITABLE事件,会由对应的命令回复处理器来处理,就是将准备好的响应数据写入socket,供客户端来读取。

命令回复处理器写完之后,就会删除这个socket的AE_WRITABLE事件和命令回复处理器的关联关系。

9. Redis中Key过期了是否立即删除?

不会立即删除。

  • 定期删除:Redis每隔一段时间就去会去查看Redis设置了过期时间的key,会再100ms的间隔中默认查看3个key。
  • 惰性删除:如果当你去查询一个已经过了生存时间的key时,Redis会先查看当前key的生存时间,是否已经到了,直接删除当前key,并且给用户返回一个空值。
  • 内存不足
10. Redis中持久化方案有哪些,有什么区别?
10.1 RDB

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复的时候将快照文件直接读到内存里

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模的数据恢复,且对应数据恢复的完整性不是非常敏感,那RDB方式要比AOP方式更加的高效。RDB的缺点是最后一次持久化后的数据可能会丢失。

RDB是Redis默认的持久化机制

  • RDB持久化文件,速度比较快,而且存储的是一个二进制的文件,传输起来很方便。

  • RDB持久化的时机:

    save 900 1:在900秒内,有1个key改变了,就执行RDB持久化。

    save 300 10:在300秒内,有10个key改变了,就执行RDB持久化。

    save 60 10000:在60秒内,有10000个key改变了,就执行RDB持久化。

  • RDB无法保证数据的绝对安全。

在redis.conf目录中添加如下内容:

#RDB持久化机制的配置
save 900 1
save 300 10
save 60 10000
#开启持久化压缩
rdbcompression yes
dbfilename dump.rdb

修改redis配置文件,添加持久化映射目录

version: '3.1'
services:
  redis:
    image: daocloud.io/library/redis:5.0.7
    restart: always
    container_name: redis
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 6379:6379
    volumes:
      - ./conf/redis.conf:/usr/local/redis/redis.conf
      - ./data:/data
    command: ["redis-server","/usr/local/redis/redis.conf"]

docker-compose down #先关闭并删除容器

docker-compose up -d #重启

进入redis后,通过redis-cli操作redis,之后通过shudown save命令持久化redis

这个时候再次进入data目录中就能发现存在了一个dump.rdb持久化文件。

再次启动redis服务之后,进入redis就会发现之前存储在redis中的数据可以再次发现!

10. 2 AOF

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

AOF持久化机制默认是关闭的,Redis官方推荐同时开启RDB和AOF持久化,更安全,避免数据丢失。

  • AOF持久化的速度,相对RDB较慢的,存储的是一个文本文件,到了后期文件会比较大,传输困难。

  • AOF持久化时机。

    appendfsync always:每执行一个写操作,立即持久化到AOF文件中,性能比较低。
    appendfsync everysec:每秒执行一次持久化。
    appendfsync no:会根据你的操作系统不同,环境的不同,在一定时间内执行一次持久化。

  • AOF相对RDB更安全,推荐同时开启AOF和RDB。

redis.conf文件中关于AOF的配置

#开启AOF
appendonly yes
#保存的文件名
appendfilename "redis.aof"

#appendfsync always
appendfsync everysec
#appendfsync no

修改好之后重启下redis

docker-compose restart

进入到redis容器中,操作redis,之后shutdown nosave命令退出redis

10.3 注意事项

同时开启RDB和AOF的注意事项:

如果同时开启了AOF和RDB持久化,那么在Redis宕机重启之后,需要加载一个持久化文件,优先选择AOF文件。

如果先开启了RDB,再次开启AOF,如果RDB执行了持久化,那么RDB文件中的内容会被AOF覆盖掉。

一致性hash()算法

测试题23

1. 冒泡排序算法
for(int i=0; i<length -1; i++){
		for(int j=0; j<length-1-i; j++){
			if(arr[j]>arr[j+1]){
				int temp = arr[j];	
				arr[j] = arr[j+1];	
				arr[j+1]=temp;
			}
		}
	}
2. synchronized锁升级过程?

对象锁
无锁-》偏向锁-》轻量级锁-》重量级锁

在这里插入图片描述

3. js中null,undefined的区别?

null:空

undefined:未定义

4. 如何防止表单重复提交?

1、JavaScript防止表单重复提交(主要用于网络延迟情况下用户点击多次submit按钮导致表单重复提交)

在jsp页面中,添加JavaScript代码来防止表单的重复提交。主要是针对在网络延迟情况下用户有时间点击多次submit按钮导致表单重复提交,使用javascript控制Form表单只能提交一次。

5. 事务的四个特性,什么是脏读、幻读、不可重复读
问题描述
脏读 (Dirty Read)一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止
不可重复读(Non-repeatable Read)一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止
幻读(Phantom Read)一个事务内多次读取一张表中的相同内容,其结果不一致。serialized-read 可防止
6. springMVC的执行流程

在这里插入图片描述

7. Lock 与 Synchronized 的区别。

区别:

  1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
  2. synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
  3. Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  5. Lock可以提高多个线程进行读操作的效率。
    在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
  6. synchronized实现的机理依赖于软件层面上的JVM,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
  7. ReentantLock继承接口Lock并实现了接口中定义的方法,除了能完成synchronized所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。
  8. 尽管Java实现的锁机制有很多种,并且有些锁机制性能也比synchronized高,但还是强烈推荐在多线程应用程序中使用该关键字,因为实现方便,后续工作由JVM来完成,可靠性高。只有在确定锁机制是当前多线程程序的性能瓶颈时,才考虑使用其他机制,如ReentrantLock等。
  9. ReentrantLock通过方法lock()与unlock()来进行加锁与解锁操作,与synchronized会被JVM自动解锁机制不同,ReentrantLock加锁后需要手动进行解锁。为了避免程序出现异常而无法正常解锁的情况,使用ReentrantLock必须在finally控制块中进行解锁操作。
8. MyBatis中#{}和${}的区别
  1. #{} ?占位符
    select * from user where username=#{name}
    select * from user where username=?
  2. 字 符 串 拼 接 s e l e c t ∗ f r o m u s e r w h e r e u s e r n a m e = ′ {} 字符串拼接 select * from user where username='字符串拼接selec**tfromuserwhereusername=′{name}’
    PreparedStatement/Statement
9. 线程池的配置参数有哪些?

corePollSize:核心线程数。在创建了线程池后,线程中没有任何线程,等到有任务到来时才创建线程去执行任务。

maximumPoolSize:最大线程数。表明线程中最多能够创建的线程数量。

keepAliveTime:空闲的线程保留的时间。

TimeUnit:空闲线程的保留时间单位。

BlockingQueue:阻塞队列,存储等待执行的任务。参数有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue可选。

ThreadFactory:线程工厂,用来创建线程

RejectedExecutionHandler:队列已满,而且任务量大于最大线程的异常处理策略。

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

10. @Autowired和@Resource之间的区别
  1. @Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
  2. @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
    @Autowired默认按类型装配(这个注解是属于spring),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) 。

测试题24

1. elasticsearch的倒排索引是什么?

将存放的数据,以一定的方式进行分词,并且将分词的内容存放到一个单独的分词库中。

当用户去查询数据时,会将用户的查询关键字进行分词。

然后去分词库中匹配内容,最终得到数据的id标识。

根据id标识去存放数据的位置拉取到指定的数据。

在这里插入图片描述

2. scroll+size分页的好处?

ES对from + size是有限制的,from和size二者之和不能超过1W

原理:

  • from+size在ES查询数据的方式:

    • 第一步现将用户指定的关键进行分词。
    • 第二步将词汇去分词库中进行检索,得到多个文档的id。
    • 第三步去各个分片中去拉取指定的数据。耗时较长。
    • 第四步将数据根据score进行排序。耗时较长。
    • 第五步根据from的值,将查询到的数据舍弃一部分。
    • 第六步返回结果。
  • scroll+size在ES查询数据的方式:

    • 第一步现将用户指定的关键进行分词。
    • 第二步将词汇去分词库中进行检索,得到多个文档的id。100id
    • 第三步将文档的id存放在一个ES的上下文中。100id
    • 第四步根据你指定的size的个数去ES中检索指定个数的数据,拿完数据的文档id,会从上下文中移除。80id
    • 第五步如果需要下一页数据,直接去ES的上下文中,找后续内容。
    • 第六步循环第四步和第五步

Scroll查询方式,不适合做实时的查询

游标curosor

# 执行scroll查询,返回第一页数据,并且将文档id信息存放在ES上下文中,指定生存时间1m
POST /sms-logs-index/sms-logs-type/_search?scroll=1m
{
  "query": {
    "match_all": {}
  },
  "size": 2,
  "sort": [					# 排序
    {
      "fee": {
        "order": "desc"
      }
    }
  ]
}

# 根据scroll查询下一页数据
POST /_search/scroll
{
  "scroll_id": "<根据第一步得到的scorll_id去指定>",
  "scroll": "<scorll信息的生存时间>"
}


# 删除scroll在ES上下文中的数据
DELETE /_search/scroll/scroll_id
// Java实现scroll分页
@Test
public void scrollQuery() throws IOException {
    //1. 创建SearchRequest
    SearchRequest request = new SearchRequest(index);
    request.types(type);

    //2. 指定scroll信息
    request.scroll(TimeValue.timeValueMinutes(1L));

    //3. 指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.size(4);
    builder.sort("fee", SortOrder.DESC);
    builder.query(QueryBuilders.matchAllQuery());
    
    request.source(builder);

    //4. 获取返回结果scrollId,source
    SearchResponse resp = client.search(request, RequestOptions.DEFAULT);

    String scrollId = resp.getScrollId();
    System.out.println("----------首页---------");
    for (SearchHit hit : resp.getHits().getHits()) {
        System.out.println(hit.getSourceAsMap());
    }


    while(true) {
        //5. 循环 - 创建SearchScrollRequest
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);

        //6. 指定scrollId的生存时间
        scrollRequest.scroll(TimeValue.timeValueMinutes(1L));

        //7. 执行查询获取返回结果
        SearchResponse scrollResp = client.scroll(scrollRequest, RequestOptions.DEFAULT);

        //8. 判断是否查询到了数据,输出
        SearchHit[] hits = scrollResp.getHits().getHits();
        if(hits != null && hits.length > 0) {
            System.out.println("----------下一页---------");
            for (SearchHit hit : hits) {
                System.out.println(hit.getSourceAsMap());
            }
        }else{
            //9. 判断没有查询到数据-退出循环
            System.out.println("----------结束---------");
            break;
        }
    }


    //10. 创建CLearScrollRequest
    ClearScrollRequest clearScrollRequest = new ClearScrollRequest();

    //11. 指定ScrollId
    clearScrollRequest.addScrollId(scrollId);

    //12. 删除ScrollId
    ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);

    //13. 输出结果
    System.out.println("删除scroll:" + clearScrollResponse.isSucceeded());

}
3. elasticsearch 搜索的过程
  1. term的查询是代表完全匹配,搜索之前不会对你搜索的关键字进行分词,对你的关键字去文档分词库中去匹配内容。

  2. terms和term的查询机制是一样,都不会将指定的查询关键字进行分词,直接去分词库中匹配,找到相应文档内容。

    terms是在针对一个字段包含多个值的时候使用。

    term:where province = 北京;

    terms:where province = 北京 or province = ?or province = ?

  1. match查询属于高层查询,他会根据你查询的字段类型不一样,采用不同的查询方式。
  • 查询的是日期或者是数值的话,他会将你基于的字符串查询内容转换为日期或者数值对待。
  • 如果查询的内容是一个不能被分词的内容(keyword),match查询不会对你指定的查询关键字进行分词。
  • 如果查询的内容时一个可以被分词的内容(text),match会将你指定的查询内容根据一定的方式去分词,去分词库中匹配指定的内容。

match查询,实际底层就是多个term查询,将多个term查询的结果给你封装到了一起。

  1. match_all:查询全部内容,不指定任何查询条件。
4. 根据如下条件写出查询的API。
 #smsContent中包含中国和平安
GET /index/type/_search{
"query":{
	"bool":{
		"should":[
{
	term:{
		"province":{
			value:"武汉"
		}
	}
},{
	term:{
		"province":{
			value:"北京"
		}
	}
}
		],
		“must”:[
	match:{
		"smsContent":{
			value:"中国"
		}
	},
	match:{
		"smsContent":{
			value:"平安"
		}
	}
		],
		“must_not”:[
	term:{
		"provideId":{
			value:"2"
		}
	}
		]
	}
}
}

5. 对象头包含哪些信息?

markword+klass word
hashcode+age+偏向标志+锁标志

6. 线程池的配置参数有哪些?

核心线程个数
最大线程个数
最大空闲时间
队列长度
拒绝策略

7. 描述一下JVM加载class文件的原理机制?

加载-》连接(验证、准备、解析)-》初始化-》使用-》卸载

8. Java 中会存在内存泄漏吗,请简单描述

Java中的内存泄露,广义并通俗的说,就是:不再会被使用的对象的内存不能被回收,就是内存泄露。

Java中的内存泄露与C++中的表现有所不同。

在C++中,所有被分配了内存的对象,不再使用后,都必须程序员手动的释放他们。所以,每个类,都会含有一个析构函数,作用就是完成清理工作,如果我们忘记了某些对象的释放,就会造成内存泄露。

但是在Java中,我们不用(也没办法)自己释放内存,无用的对象由GC自动清理,这也极大的简化了我们的编程工作。但,实际有时候一些不再会被使用的对象,在GC看来不能被释放,就会造成内存泄露。

9. Statement和PreparedStatement有什么区别?

后者的效率比前者高

在使用preparedStatement对象执行sql时候 命令被数据库编译和解析,然后被放到命令缓冲区, 然后每当执行同一个preparedStatement时候,他就被再解析一次, 但不会在编译,在缓冲区中可以发现预编译的命令,并且可以重新使用。 如果你要写Insert update delete 最好使用preparedStatemen在有大量用户的企业级应用软件中,经常会执行相同的sql 使用preparedStatement会增加整体的性能。

preparedstatement能有效防止SQL注入

注入漏洞是由于在参数值改变了sql的执行逻辑,例如 //username正常情况下应该是一个用户名只包含数字或者英文字母, //但是当用户填写的是下面的串的时候,注入漏洞就发生了

String  username="  a' or 1=1 ";//注意:此时的1=1是永真条件
    String  pssword="xxx";
    String sql="select * from users where password='"+password+"' and user_name = ' "+username;123

此时不管密码的什么都能查询到数据。相当于绕过验证了。 PreparedStatement的参数注入功能会把参数里的特殊字符进入转义, 单引号这样的是会被转义的,所以sql的逻辑不会因为参数值发生改变 注入漏洞就不可能发生了

10. synchronized锁升级过程

0 01 无锁
1 01 偏向锁
0 00 轻量级锁
0 10 重量级锁

测试题25

1. Spring Boot、Spring MVC 和 Spring 有什么区别?

Spring:提供Ioc/DI、AOP功能的一种框架
SprngMVC:基于Spring实现MVC结构的框架
SpringBoot:基于Spring实现自动配置的框架

2. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

3. Spring Boot 自动配置原理是什么?

在启动时装载META-INF/spring.factories文件中的以EnableAutoConfiguration为key的bean,这些对象都有生效的各自条件

4. 阐述JDBC操作数据库的步骤。

1.记载驱动
2.建立连接
3.创建声明对象
4.执行SQL
5.解析结果
6.关闭

5. ArrayList、Vector、LinkedList的存储性能和特性。

ArrayList底层是数组,扩容是1.5,查询快,增删该慢
Vector:底层也是数组,是线程安全,扩容是2
LinkedList:双向链表,增删改快,查询慢

6. 阐述final、finally、finalize的区别

final:常量、防止方法重写、防止被继承
finally:异常
finalize:gc

7. 抽象类(abstract class)和接口(interface)有什么异同?
  1. 抽象类:抽象类是指这个对象是什么

  2. 接口:接口是指这个对象能做什么

    举例: 定义一个狗类(抽象类):哈士奇,金毛都属于狗类(实现类)狗:睡觉,拆家…可以定义一个接口,让实现类去实现接口

  3. 因此在Java语言中,一个类只能继承一个类(抽象类)(正如狗不可能同时是生物和非生物),但是接口可以多继承,一个类能够实现多个接口。

  4. 接口中的所有方法是抽象的(abstract修饰)而抽象类是声明方法而不去实现它的类。

  5. 接口可以多继承,抽象类单继承

  6. 接口定义方法,不能实现,而抽象类可以实现部分方法

  7. 接口中的基本数据类型为static,而抽象类不是。

注:
抽象类的功能远超过接口,但是,定义抽象类的代价比较高。因为高级语言来说(从实际设计出发也是),每个类只能继承一个类。在这个类中你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是接口是针对一个动作的实现,而且一个类能够继承多个接口,在设计中难度会相对降低。

8. Redis如何解决数据一致性问题?

延迟双删
1.删除缓存
2.修改数据库
3.延迟一段时间(时间有项目自行去确定)
4.删除缓存

将并行边串行,“流量削峰”

9. 什么是缓存预热?

将热点数据线加载到缓存中

10. spring bean 的生命周期

单例:启动-》构造对象-》set-》后置处理的前置过程-》init-》后置处理器的后置过程-》使用-》销毁

测试题26

1. 缓存穿透与缓存击穿的区别,及解决办法?

缓存处理流程

前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

在这里插入图片描述

二、缓存穿透

​ 描述:

​ 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决方案:

接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

三、缓存击穿

描述:

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

解决方案:

设置热点数据永远不过期。
加互斥锁,互斥锁参考代码如下:

Public static String getData(String key) throws InterruptedException{
    //从缓存中读取数据
    String result = getDataFromRedis(key);
    //缓存中不存在数据
    if(result == null) {
        //去获取锁,获取成功,去数据库取数据
        if(reenLock.tryLock()){
            //从缓存中获取数据
            result = getDataFromMysql(key);
            //更新缓存数据
            if(result != null) {
                setDataToCache(key,result);
            }
            //释放锁
            reenLock.unlock();
        }
        //获取锁失败
        else{
            //暂停100ms再重新去获取数据
            Thread.sleep(100);
            result = getData(key);
        }
    }
    return result;
}

​ 说明:

​ 1)缓存中有数据,直接走上述代码13行后就返回结果了

​ 2)缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待100ms,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。

​ 3)当然这是简化处理,理论上如果能根据key值加锁就更好了,就是线程A从数据库取key1的数据并不妨碍线程B取key2的数据,上面代码明显做不到这点。

四、缓存雪崩

描述:

缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是:缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案:

缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
设置热点数据永远不过期。

2. Redis如何保证数据一致性?
  • 更新的时候,先删除缓存,然后再更新数据库
  • 读的时候,先读缓存;如果没有的话,就读数据库,同时将数据放入缓存,并返回响应
3. redis的过期策略以及内存淘汰机制

​ volatile-lru
​ allkeys-lru
​ volatile-lfu
​ allkeys-lfu
​ volatile-random
​ allkeys-random
​ volatile-ttl
​ noeviction

4. Java中垃圾收集的方法有哪些?

​ 引用计数算法
​ 根搜索算法
​ 分代算法
​ 标记整理
​ 标记清除
​ 复制整理

5. spring bean 的生命周期

单例:启动-》构造对象-》set-》后置处理的前置过程-》init-》后置处理器的后置过程-》使用-》销毁

6. spring 常用的注入方式有哪些?

set
构造
自动

7. 聚集索引与非聚集索引的区别

聚集索引:叶子节点中直接存储了的数据
非聚集索引:叶子节点中值存在了索引数据和数据的具体地址

8. 事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?

读未提交 读已提交 可重复读 串行化
脏读 1 1 1
不可重复读 1 1
幻读 1

9. SQL优化方法有哪些?

SQL语句的优化
limit 1
like “%xxx”
select 字段名
小表驱动大表
like存在锁表
“最左匹配原则”
A B
where A条件 and B 条件

10. 什么是Java的双亲委派机制?

Boostrap Classloader->ExtenderClassloader->App Classloader->自定义加载器

测试题27

1. 什么是RabbitMQ?为什么使用RabbitMQ?

RabbitMQ是开源,基于Erlang语言的,符合AMQP协议的消息中间件
解耦、异步、削峰

2. 如何确保消息正确地发送至RabbitMQ?

Confirm确认机制
Return机制

3. 如何确保消息接收方消费了消息?

Ack机制

4. 如何解决丢数据的问题?

交换机持久化机制
队列持久化
数据持久

5. 多个消费者监听一个队列时,消息如何分发?

默认是平均、按照处理的速度确定

6. 无法被路由的消息去了哪里?

消息丢失

7. 消息基于什么传输?

信道,TCP

8. 如何确保消息不丢失

生产者
confirm+return
队列
持久化

消费者
ACK

9. RabbitMQ消息模型有哪些,区别是什么?

HelloWOrld
Work
Fanout
Direct
Topic

10. Redis集群,集群的原理是什么?

是否使用过Redis集群,集群的原理是什么?

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。

Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

集群要实现的目的是要将不同的 key 分散放置到不同的 redis 节点,这里我们需要一个规则或者算法,

通常的做法是获取 key 的哈希值,然后根据节点数来求模,但这种做法有其明显的弊端,当我们需要增加或减少一个节点时,会造成大量的 key 无法命中,这种比例是相当高的,所以就有人提出了一致性哈希的概念。

一致性哈希有四个重要特征:

均衡性:也有人把它定义为平衡性,是指哈希的结果能够尽可能分布到所有的节点中去,这样可以有效的利用每个节点上的资源。

*单调性:当节点数量变化时哈希的结果应*尽可能的保护已分配的内容不会被重新分派****到新的节点。

分散性和负载:这两个其实是差不多的意思,就是要求一致性哈希算法对 key 哈希*应尽可能的避免重复***。

但是:

Redis 集群没有使用一致性hash, 而是引入了**哈希槽**的概念。

Redis集群有**16384个哈希槽,每个key通过**CRC16**校验后*对16384取模*来决定放置哪个槽(Slot),集群的每个节点负责一部分hash槽。

这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。

使用哈希槽的好处就在于可以方便的添加或移除节点。

测试题28

1. 消息队列消息重复问题如何解决?

Redis锁机制实现

2. 什么是TTL队列、什么是死信队列?

TTL:time to live

一个队列中的消息在某段时间后还没处理,那么这个消息就要自动失效,就自动从队列中被删除

私信队列:当消息在队列中变成死信之后,它自动被push到另外一个队列中,那么这个队列就是死信队列!

死信的条件

  • 发送的消息被拒绝了
  • 消息的ttl时间到期了
  • 队列达到了最大长度,那么后面push的消息也会进入死信
3. 存储引擎了解多少?MyISAM是怎么实现的?为什么就不能支持事务?

InnoDB B+树 索引结构存放数据了
MyISAM B+数据 索引和数据分开 每条SQL语句都是原子操作

4. 深度分页原理,深度分页会有什么问题

ES对from + size是有限制的,from和size二者之和不能超过1W

原理:

  • from+size在ES查询数据的方式:

    • 第一步现将用户指定的关键进行分词。
    • 第二步将词汇去分词库中进行检索,得到多个文档的id。
    • 第三步去各个分片中去拉取指定的数据。耗时较长。
    • 第四步将数据根据score进行排序。耗时较长。
    • 第五步根据from的值,将查询到的数据舍弃一部分。
    • 第六步返回结果。
  • scroll+size在ES查询数据的方式:

    • 第一步现将用户指定的关键进行分词。
    • 第二步将词汇去分词库中进行检索,得到多个文档的id。100id
    • 第三步将文档的id存放在一个ES的上下文中。100id
    • 第四步根据你指定的size的个数去ES中检索指定个数的数据,拿完数据的文档id,会从上下文中移除。80id
    • 第五步如果需要下一页数据,直接去ES的上下文中,找后续内容。
    • 第六步循环第四步和第五步

Scroll查询方式,不适合做实时的查询

​ scroll+size,不能实时分页
​ from+size,分页的数据量不宜过多

游标curosor

5. 项目中rabbitmq哪里用到了,做了什么?

es数据同步
redis数据同步

6. http 与 https 的区别

http:超文本传输协议

https = http + SSL

7. linux怎么查看日志的?

tail -f 日志文件

8. springboot是如何实现自动装配的?

@EableAutoConfiguartion->Meta-INF/spring.factories文件中的EnableAutoConfiguration为key所有value生成对应的Bean对象

9. Redis的持久化,然后说一下各自优缺点

Redis 提供两种持久化机制 RDB 和 AOF 机制:

1、RDBRedis DataBase)持久化方式:是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件。

持久化 结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。

优点:

1、只有一个文件 dump.rdb,方便持久化。

2、容灾性好,一个文件可以保存到安全的磁盘。

3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能)

4.相对于数据集大时,比 AOF 的启动效率更高。

缺点:

1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生 故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)

2、AOFAppend-only file)持久化方式:是指所有的命令行记录以 redis 命令请 求协议的格式完全持久化存储)保存为 aof 文件。

优点:

1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。

2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。

3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))

缺点:

1、AOF 文件比 RDB 文件大,且恢复速度慢。

2、数据集大的时候,比 rdb 启动效率低

10. shiro是怎么做权限控制的?

Subject->SecurityMananger
Authenticator->Realm->认证
Authorizer->Realm->授权
认证-》授权

d

  • 第三步将文档的id存放在一个ES的上下文中。100id
  • 第四步根据你指定的size的个数去ES中检索指定个数的数据,拿完数据的文档id,会从上下文中移除。80id
  • 第五步如果需要下一页数据,直接去ES的上下文中,找后续内容。
  • 第六步循环第四步和第五步

Scroll查询方式,不适合做实时的查询

​ scroll+size,不能实时分页
​ from+size,分页的数据量不宜过多

游标curosor

5. 项目中rabbitmq哪里用到了,做了什么?

es数据同步
redis数据同步

6. http 与 https 的区别

http:超文本传输协议

https = http + SSL

7. linux怎么查看日志的?

tail -f 日志文件

8. springboot是如何实现自动装配的?

@EableAutoConfiguartion->Meta-INF/spring.factories文件中的EnableAutoConfiguration为key所有value生成对应的Bean对象

9. Redis的持久化,然后说一下各自优缺点

Redis 提供两种持久化机制 RDB 和 AOF 机制:

1、RDBRedis DataBase)持久化方式:是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件。

持久化 结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。

优点:

1、只有一个文件 dump.rdb,方便持久化。

2、容灾性好,一个文件可以保存到安全的磁盘。

3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能)

4.相对于数据集大时,比 AOF 的启动效率更高。

缺点:

1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生 故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)

2、AOFAppend-only file)持久化方式:是指所有的命令行记录以 redis 命令请 求协议的格式完全持久化存储)保存为 aof 文件。

优点:

1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。

2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。

3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))

缺点:

1、AOF 文件比 RDB 文件大,且恢复速度慢。

2、数据集大的时候,比 rdb 启动效率低

10. shiro是怎么做权限控制的?

Subject->SecurityMananger
Authenticator->Realm->认证
Authorizer->Realm->授权
认证-》授权


版权声明:本文为zhu_fangyuan原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。