2022面试题

面试题
 

关系型数据库是指采用关系模型来组织数据信息的数据库。
常见关系型数据库:Mysql、Oracle、PostgreSQL、SQL Server、Access、Sybase

常见非关系型数据库:Redis、MongoDB、BigTable、MemcacheDB等
非关系型数据库是指采用键值对的模型来存储数据。

redis数据类型(说不全没关系,面试官想问的是hash)
string list set zset hash
zset是一个有序集合,每个成员都有一个分数与之对应,成员不可以重复,但是数是可以重复的,zset会自动用分数对成员进行排序
zst常用命令:zadd添加语句
zcard key查看zset集合内成员个数
api如何调用的hash。 hset
Hash是 键-值 类型,值类型类似map结构,即 key-{{field1,value1},...,{fieldN,valueN}},更适合来保存对象,例商品信息

HSET key field value [field value ...]

HGET key field

redis持久化。rdb快照

redis过期删除
redis集群模式 主从模式 哨兵模式
缓存击穿:某个热点数据并发高,读缓存没读到,并发读数据库造成过大压力

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决方案:
1、热点数据不设置过期时间。 2、在凌晨或者用户量少的时候开定时任务去保证热点数据完整性。 3、做类似双重检查锁的操作,一般现在架构都是微服务了,外层开个分布式锁,锁内再尝试去拿缓存,拿不到就去查数据库,查到之后放回redis内

 穿透 :某个数据缓存和数据库都没读到,导致所有请求都落到数据库上

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1、从缓存取不到的数据,在数据库中也没有取到,可以写一个默认值进去,比如-1,设置较短的过期时间,查询到缓存值为-1就直接返回,等待过期之后再去数据库查。 2、使用布隆过滤器(Bloom Filter),判断key是否存在,存在的话去数据库查,查完再放回redis,Bloom Filter里面不存在的话,则直接返回或者报错。

雪崩:大面积数据读缓存没读到,全部读数据库

缓存雪崩是指缓存同一时间大面积的失效,后面的请求都会落到数据库上(一般程序是先查redis,redis没有的话就会查数据库,然后将值再放回redis),造成数据库短时间内承受大量请求而崩掉。
解决方案:
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。 2、一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。 3、给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。
为什么用redis
nosql数据库存储于缓存中,查询速度快
存储格式丰富,支持基础类型和各种集合对象
部署简易
使用场景:
存储 缓存 用的数据;
需要高速读/写的场合使用它快速读/写;

    ◦    redis的计数count,来实现签到场景
答:incr。每签到一次,key递增一次
redis> SET page_view 20
OK
redis> INCR page_view
(integer) 21
redis> GET page_view # 数字值在 Redis 中以字符串的形式保存
"21"

为什么需要 Elasticsearch?
用数据库,也可以实现搜索的功能,为什么还需要搜索引擎呢?

传统关系型数据库是非常胜任「精确匹配」而「相关性匹配」更贴近人的思维方式。

搜索和分析,不只是搜索,还有分析Elasticsearch 真正强大之处在于可以从无规律的数据中找出有意义的信息,实时计算的一种常见方案,是数据产生后,通过消息队列(比如kafka)推给实时计算平台 storm,计算后,再把数据存到 ES

原理

关系型数据库,把原本非常形象的对象,拍平了,拍成各个字段,存在数据库,查询时,再重新构造出对象;ES则是文档存储,把对象原原本本地放进去,取出时直接取出。
 
elasticsearch
问题 es版本升级,修改端口 升级完es数据丢了
原因:没有配置es存储数据的地方这个配置
path.data
es脑裂 不同的节点对主节点mater的选择产生分歧,出现了多个mateer竞争,导致主片和副本的识别也出现了分歧,对一些分歧🀄️的分片标识为坏片
解决方案:将mateer和data节点分离
主节点node.master:true
node.data:false
其他节点相反,这样master和data节点就分开了
    ◦    
    ✓    es是先查数据库还是先查es,量级多少,如何解决es数据延时的问题
设置刷新策略,写完就刷新

    ◦    如何解决es数据延时不同步的问题
ES添加数据延迟的问题是他的缓存问题refresh和qush,添加数据先落到缓冲区中,缓冲区的数据无法被及时查询到,在经过
Buffer缓冲区执行refresh后,数据才会落到可以查询的cache里。refresh默认1s一次,如果不怕集群出问题,可以设置刷新策
略为IMMEDIATE,每次写操作
后,立即刷新。

ES中的倒排索引是什么
答:lucene的倒排索引,它适用于快速的全文搜索.
(倒排索引),即由文件ID对应到关键词,转换为关键词到文件ID的映射,每个关键词都对应着多个ID(多个id对应多个文件)并保存到倒排表中,查询时会将内容进行分词后在倒排表中进行查询,最后匹配数据即可。这些文件中都出现这个关键词。
    ◦    什么是近实时搜索?如何优化
答:在ES和磁盘之间是文件系统缓存,默认情况下每个分片会每秒刷新一次,即refresh,即刷新文件系统缓存。这就是为什么我们说 Elasticsearch 是 近实时搜索:文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。这些行为可能会对新用户造成困惑:他们索引了一个文档然后尝试搜索它,但却没有搜到。这个问题的解决办法是用 refresh API 执行一次手动刷新:/users/_refresh。
但不是每时每刻都需要刷新的,当建一个大的索引时,可以先关闭自动刷新,待开始使用时再调回来

 关闭自动刷新
PUT /users/_settings
{ "refresh_interval": -1 } 
# 每一秒刷新
PUT /users/_settings
{ "refresh_interval": "1s" }

    ◦    如何解决es数据延时不同步的问题
ES添加数据延迟的问题是他的缓存问题refresh和qush,添加数据先落到缓冲区中,缓冲区的数据无法被及时查询到,在经过
Buffer缓冲区执行refresh后,数据才会落到可以查询的cache里。refresh默认1s一次,如果不怕集群出问题,可以设置刷新策
略为IMMEDIATE,每次写操作
后,立即刷新。
 
    ◦    Elasticsearch 集群脑裂问题?有哪些解决方法?

“脑裂”问题可能的成因:(有两个master)

网络问题:集群间的网络延迟导致一些节点访问不到 master,认为 master 挂掉了从而选举出新的
master,并对 master 上的分片和副本标红,分配新的主分片
节点负载:主节点的角色既为 master 又为 data,访问量较大时可能会导致 ES 停止响应造成大面积延
迟,此时其他节点得不到主节点的响应认为主节点挂掉了,会重新选取主节点。
内存回收:data 节点上的 ES 进程占用的内存较大,引发 JVM 的大规模内存回收,造成 ES 进程失去响应。

解决方案:

⾓⾊分离:即master节点与data节点分离,限制⾓⾊;数据节点时需要承担存储和搜索的⼯作的,压⼒会很⼤。所以如果该节点同时作为候选主节点和数据节点,那么⼀旦选上它作为主节点了,这时主节点的⼯作压⼒将会⾮常⼤,出现脑裂现象的概率就增加了。
减少误判:配置主节点的响应时间,在默认情况下,主节点3秒没有响应,其他节点就认为主节点宕机了,那我们可以把该时间设置得长⼀点,该配置是:discovery.zen.ping_timeout:5
选举触发:discovery.zen.minimum_master_nodes:1(默认是1),该属性定义的是为了形成⼀个集群,有主节点资格并互相连接的节点的最⼩数⽬。
⼀个有10节点的集群,且每个节点都有成为主节点的资格,
discovery.zen.minimum_master_nodes参数设置为6。
正常情况下,10个节点,互相连接,⼤于6,就可以形成⼀个集群。
若某个时刻,其中有3个节点断开连接。剩下7个节点,⼤于6,继续运⾏之前的集群。⽽断开的3个节点,⼩于6,不能形成⼀个集群。
该参数就是为了防⽌脑裂的产⽣
建议设置为(候选主节点数/2)+1。

es分词器?


kafka面试题
    ◦    dmq发消息丢了怎么办?
答:生产者丢失消息的情况(网络问题)——生产者send方法发送消息(异步)我们可以通过get方法获取调用结果对结果判断消息是否成功发送
kafkaTemplate.send(topic, o).get()

sendResult.getProducerRecord().topic()

kafak丢失消息的情况—-持久化问题(假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出一个 leader ,但是 leader 的数据还有一些没有被 follower 副本的同步的话,就会造成消息丢失。)
解决办法就是我们设置 acks = all。a
acks 的默认值即为1,代表我们的消息被leader副本接收之后就算被成功发送。当我们配置 acks = all 代表则所有副本都要接收到该消息之后该消息才算真正成功被发送。

消费者消费消息丢失的情况—-
每次在真正消费完消息之后再自己手动提交 offset

    ◦    与其他消息队列相比,kafka的优势在哪里
答:性能优秀;兼容性高
    ◦    kafka的消息模型?
答:发布-订阅模型
传统的队列模型一条消息只能被一个消费者使用
kafka使用主题(Topic) 作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过topic传递给所有的订阅者,在一条消息广播之后才订阅的用户则是收不到该条消息的。
RocketMQ 的消息模型和 Kafka 基本是完全一样的。唯一的区别是 Kafka 中没有队列这个概念,与之对应的是 Partition(分区)。

分区用来持久化消息,副本leader存储消息,副本follower拷贝leader的消息

    ◦    分区副本区别

kafka有三层形式,kafka有多个主题,每个主题有多个分区,每个分区又有多条消息。
而每个分区可以分布到不同的机器上,这样一来,从服务端来说,分区可以实现高伸缩性,以及负载均衡;每个分区又可以有多个副本。这多个副本中,只有一个是leader,而其他的都是follower副本。仅有leader副本可以对外提供服务

    ◦    zookeeper对应kafaka的作用?
答:ZooKeeper 主要为 Kafka 提供元数据的管理的功能。
topic注册:topic在各个分区与kafka的联系关系是由注册中心维护的
负载均衡
zookeeper每次leader节点挂掉时,都会通过内置id,来选举处理了最新事务的那个follower节点。


    ◦    kafka如何保证消息不重复?

kafka出现消息重复消费的原因:
    •    服务端侧已经消费的数据没有成功提交 offset(根本原因)。
    •    Kafka 侧 由于服务端处理业务时间长或者网络链接等等原因让 Kafka 认为服务假死,触发了分区 rebalance。
解决方案:
    •    消费消息服务做幂等校验(比如redis的set),幂等校验就是生产者消费者使用唯一的topic名称
    •    将 enable.auto.commit 参数设置为 false,关闭自动提交,开发者在代码中手动提交 offset。那么这里会有个问题:什么时候提交offset合适?
    •    处理完消息再提交:依旧有消息重复消费的风险,和自动提交一样
    •    拉取到消息即提交:会有消息丢失的风险。允许消息延时的场景,一般会采用这种方式。然后,通过定时任务在业务不繁忙(比如凌晨)的时候做数据兜底。

多线程callable runable的区别
答:异;callable的核心是call方法有返回值,runable的run方法没有返回值,因为runnable是java1.1就有了,所以他不存在返回值,后期在java1.5进行了优化,就出现了callable,就有了返回值和抛异常;
runable异常必须try catch处理,call异常可以抛出
同:都可以用于Executors,ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务

线程池如何使用,关键属性是什么
答:ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务
new ThreadPoolExecutor()
核心属性是ctl,用来记录线程池工作状态和工作线程数


乐观锁使用场景锁怎么用的
1:适合操作比较快的场景,互联网高并发高可用高性能场景下,很少使用悲观锁了,乐观锁方案可以胜任非常高的响应速度
2:还有个场景是concurrenthashmap中,为了保持自己的线程安全,没有hash冲突时currenthashmap进行put操作的时候使用cas机制,有hash冲突时使用synchronized加锁处理

乐观锁:乐观的认为这个操作不会被别的线程打断,成功就执行,不成功就失败,冲突检测和数据更新,java的juc包下有大量乐观锁的实现
乐观锁典型实现方式CAS:compare and swap
n++
0读到了,进行加一操作,1往回写的时候,判断原值是否还是0(如果被改了则从头),如果还是0,说明运算加的时候没人修改,就返回1完成加操作

问题:ABA(0可能被改过1,又改回0)
加版本解决,时间戳数字或者boolean类型
通过Atomic保证cas原子性


    ◦    自旋锁和互斥锁的区别?
答:自旋锁加锁失败后,线程会忙等待,直到拿到锁
互斥锁加锁失败后,线程释放cpu给其他线程
当加锁失败时,互斥锁用「线程切换」来应对,自旋锁则用「忙等待」来应对

执行时间短线程数少就用自旋锁,自旋可以用while true来实现,但最好用CPU提供的PAUSE指令来实现忙等

    ◦    juc下面的包了解吗
JUC是java.util.concurrent包的缩写
主要提供了显示锁,如重入锁ReentrantLock)和读写锁(ReadWriteLock)。核心是AQS这个抽象队列同步器框架。J.U.C包中很多工具类都是基于AQS实现的

答:处理线程相关类
例如:以JDK1.8为例JUC下有两个子包atomic和locks,atmoic中主要定义了一些原子操作的类,而locks中主要定义了基于AQS(AbstractQueuedSynchronzer)实现的加锁机制

AQS是一个抽象类,其类中定义了一系列方法,而所有的方法都是通过对state变量进行原子从操作来进行锁的实现,其内维护了一个双向链表用作获取锁的队列。
        AQS定义两种资源共享方式:Exclusive(独占,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。
        JUC包下还有其他关于原子操作的类,以ConcurrentHashMap为例,当对其进行put时,如果未发生hash冲突都是采用CAS方式实现线程安全的,如果发生冲突需要采用synchronized进行加锁处理。

例如:Future
Future是一个接口,我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。就相当于下了一张订货单,一段时间后可以拿着提订单来提货,这期间可以干别的任何事情。其中Future 接口就是订货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。它经常配合线程池来一起工作,将任务交给线程池去处理。

FutureTask是一个实现类,它实现了Runnable接口,配合Callable接口创建线程。Callable接口的call()方法作为线程执行体,call可以有返回值,也可以抛出异常。Callable对象不能直接作为Thread的目标,但用Future可以完成

public static void main(String[] args)throws Exception{
        FutureTask<Integer> task=new FutureTask<Integer>(new Callable(){public Integer call(){ return 1+2+3+4;}}); //匿名内部类
        new Thread(task).start();
        System.out.println("做自己的事,计算1+2+3+4交给另一个线程完成\n");
        System.out.println("返回获取结果 "+task.get());
        
    }

结果:
做自己的事,计算1+2+3+4交给另一个线程完成
返回获取结果 10

2: CountDownLatch 
这个类是一个同步计数器,主要用于线程间的控制

3: CyclicBarrier
该类从字面理解为循环屏障,它可以协同多个线程,让多个线程在这个屏障前等到,直到所有线程都到达了这个屏障时,再一起执行后面

Jvm内存模型

JVM 由类加载器子系统、运行时数据区、执行引擎以及本地方法接口组成

    1.    java代码执行过程如下
java源文件通过编译器编译成字节码程序,再通过jvm将每一条指令翻译成不同平台机器码,通过特定平台运行

运行时数据区,即jvm内存结构图如下图

    ◦    运行时数据区存储了哪些数据?
    1.    程序计数器
    2.    java栈
    3.    本地方法栈
    4.    堆
    5.    方法区
java中堆和栈的区别?
最主要的区别就是栈内存是用来存储局部变量和方法调用。
而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。凡是new建立的都是在堆中

    ◦    常用垃圾回收器
    1.    gc分类?
按线程数:并行垃圾回收器:Parallel Collector. 同一时间段内只有一个cpu执行垃圾回收操作.用户线程等待.
        串行垃圾回收期:Serial Collector.同一时间段内可以有多个cpu执行垃圾回收操作,用户线程等待.
按压缩方式:压缩式,内存有序.  非压缩式:内存无序.
按工作方式:并发式,及并发GC,用户线程和垃圾回收器同时交替进行.
         独占式,垃圾回收线程进行时,用户线程需要等待.
按工作区分:年轻代,老年代.
2.gc性能指标?
吞吐量;用户线程时间/ 垃圾回收执行时间 + 用户线程执行时间. 吞吐量优先意味着 单位时间内STW时间最短.

暂停时间:垃圾回收的时,用户线程等待的时间

现在的标准:保证吞吐量的情况下,尽量降低暂停时间.

3.gc是什么,为什么要gc

在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的

4.Java 中都有哪些引用类型?

强引用:发生 gc 的时候不会被回收。
软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
弱引用:有用但不是必须的对象,在下一次GC时会被回收。
虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。

    •    巧用弱引用解决内存泄露

5.详细介绍一下 CMS 垃圾回收器?

CMS 是英文 Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。
CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。

6.新生代垃圾回收器和老年代垃圾回收器都有哪些?有什么区别?

新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。


spring套餐面试题

    ◦    spirng框架解决循环依赖?
循环依赖是指A类依赖b类,b类依赖c类,c类又依赖a类
1:spring只能解决单例模式下循环依赖,通过二级缓存和三级缓存
2: 对于类A和类B都是通过构造器注⼊的情况,可以在A或者B的构造函数的形参上加个@Lazy注解实现延迟加载。
⽐如,类A的创建:A a=new A(B),需要依赖对象B,发现构造函数的形参上有@Lazy注解,那么就不直接创建B了,⽽是使⽤动态代理创建了⼀个代理类B1,此时A跟B就不是相互依赖了,变成了A依赖⼀个代理类B1,B依赖A。但因为在注⼊依赖时,类A并没有完全的初始化完,实际上注⼊的是⼀个代理对象,只有当他⾸次被使⽤的时候才会被完全的初始化。

    ◦    springboot的创建bean的原理javabean的配置原理
    •    
    •    @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
    •    Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
    •    当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显示指定名称,@Resource可以通过 name 属性来显示指定名称。

    ◦    spring的ioc和aop
ioc(控制反转)实现的方式有依赖注入,就是A类需要B类的对象,一般的方法是new个B类,利用IOC就只需要定义一个私有的B的成员变量,容器运行时会自动创建一个B类对象并将引用自动注入给成员变量
    1.    依赖注入的实现方法:构造方法注入,setter方法注入
    2.    依赖注入的相关注解:@autowired 自动按类型注入 @Resource直接按照bean的id注入,只能注入bean类型@Value注入基本数据类型和String类型
    3.    如何通过注解创建 Bean?
         @Component 把当前类对象存入Spring 容器中,相当于在 xml 中配置一个 bean 标签。value 属性指定bean 的id,默认使用当前类的首字母小写的类名。@Controller,@Service, @Repository 三个注解都是 @Component 的衍生注解,作用及属性都是檬一样的,只是提供了更加明确语义,@Controller 用于表现层,@Service用于业务层,@Repository用于持久层。如果注解中有且只有一个 value 属佳要赋值时可以省路 value。
4.如何通过注解配置文件?
@Confiquration用于指定当前类是-
一个springl配置类,当创建容器时会从该类上加载注解,value属性用于指定配置类的字节码

5.BeanFactory、FactoryBean 和 ApplicationContext 的区别?

BeanFactory 是一个 Bean工厂,使用简单工厂模式,是Sprina loC 容器顶级接口,可以理解为含有Bean 集合的工厂类,作用是管理 Bean,包括实例化、定位、配置对象及建立这些对象间的依赖
BeanFactory 实例化后并不会自动实例化 Bean,只有当 Bean 被使用时才实例化与装配依赖关系,属于延迟加载,适合多例模式。
    FactoryBean 是一个工厂Bean,使用了工厂方法模式,作用是生产其他 Bean 实例,可以通过实现该接口,提供一个工厂方法来自定义实例化 Bean 的设辑。FactoryBean 接口由 BeanFactory 中配置的对象实现,这些对象本身就是用于创建对象的工厂,如果-
- 个Bean 实现了这个接口,那么它就是创建
对象的工厂 Bean,而不是 Bean 实例本身
     ApplicationConext 是 BeanFactory 的子接口,扩展了 BeanFactory 的功能,提供了支持国际化的文本消息,统一的资源文件读取方式,事件传插以及应用层的特别配置等。容器会在初始化时对配置的
Bean 进行预实例化,Bean 的依赖注入在容器初始化时就已经完成,厲于立即加载,适合单例模式一般推荐使用。

AOP是什么?
    1.    aop是面向切面编程,就是将代码中重复的部分抽取出来
    2.    spring根据类是否实现接口来判断动态代理方式
    3.    常见场景包括权限认证自动缓存日志
    4.    @Aspect注解 声明被注解的类是一个切面bean
    1.    其中aspectjrt 的jar包中提供了我们编写切片过程中所需要的 @Pointcut,@After,@Aspect,@Before,@Around等注解。

 如何选用集合
    ◦    需要根据键值获取元素就用map下的集合,需要排序就treemap,不需要排序就hashmap,需要保持顺序就Linkedhasap(因为它双向链表),需要线程安全就concirrenthashmap
    ◦    当我们只需要存放元素值,就选择实现collection接口的集合,需要元素不可重复就用set,treeset比hashset需要排序,不需要元素唯一就用arraylist或linkedlist,根据增删查的速度要求选择不同list


HashMap为什么是非线程安全的?
想要解决这个问题,答案很简单,因为源码里面方法全部都是非线程安全的呀,你根本找不到synchronized这样的关键字。保证不了线程安全。于是出现了Concurrenthashmap

为什么重写equals方法就必须重写hashcode方法
java顶级父类Object类,有两个方法很特殊,equals和hashcode
举例,通过源码我们能看到,String对象在调用equals方法比较另一个对象时,除了认定相同地址值的两个对象相等以外,还认定对应着的每个字符都相等的两个String对象也相等,即使这两个String对象的地址值不同(即属于两个对象)

也就是说,被String类中的equals方法认定为相等的两个对象拥有两个不同的哈希值(因为他们的地址值不同)。问题分析到这一步,原来的问题“为什么重写equals方法就得重写hashCode方法”已经结束了,它的答案是“因为必须保证重写后的equals方法认定相同的两个对象拥有相同的哈希值”。同时我们顺便得出了一个结论:“hashCode方法的重写原则就是保证equals方法认定为相同的两个对象拥有相同的哈希值”。


MyBatis 中#和$符号的区别
#相当于对数据 加上 双引号,$相当于直接显示数据
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id". 2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的值是id,则解析成的sql为order by id. 3. #方式能够很大程度防止sql注入。 4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名、字段名. 6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
字符串替换 默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用: ORDER BY ${columnName} 这里MyBatis不会修改或转义字符串。
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。

springmvc常用注解
request mapping和requestbody

2022年3月18日 06:49

 
2022年3月18日 07:09
为什么不用索引查询慢
单纯的内存运算是很快的,但从磁盘中取数据到内存中是相对慢的,当表中有大量数据时,内存与磁盘交互次数大大增加,这就导致了查询效率低下。
 
cpu。工人。逻辑处理
内存。车间。加工 
磁盘。仓库。数据存储
为什么索引查询快
因为相对于cpu和内存,磁盘io(指输入/输出(Input/Output)。硬盘IO就是指对字节的读取速度,即硬盘的读写能力)开销很大,非常容易成为系统的性能瓶颈;所以使用索引减少了查询过程中的io次数,那么它是如何做到的呢,使用B+树(平衡多路查找树)

B+树简略示意图:
<img src="https://pic4.zhimg.com/v2-2124a9725b5e80e258b22fe8d73b5d8b_b.jpg" data-caption="" data-size="normal" data-rawwidth="750" data-rawheight="276" class="origin_image zh-lightbox-thumb" width="750" data-original="https://pic4.zhimg.com/v2-2124a9725b5e80e258b22fe8d73b5d8b_r.jpg"/>

再看B+树相对于B树的两个特点:
数据只出现在叶子节点
所有叶子节点增加了一个链指针

B+树叶子节点有指针进行相连,因此在做数据遍历时,只需对叶子结点进行遍历即可


 
用户面登录时序

app    服务器    数据库    缓存    opengw
-》用户请求携带token                
                校验at合法性
    返回用户账号信息            
        -》根据unieid查询用户信息        
    《-返回用户信息            
    判断用户信息是否存在-》为空创建用户            
    判断用户登录信息是否存在            
        存在-更新登录信息;不存在-新增登录信息        
            保存用户信息到缓存    
    返回tooen等信息            

事务隔离级别
原子性。要么成功要么失败
一致性。事务执行前后数据库状态保持一致
隔离性。事务与食物之间互不影响
持久性。数据一旦提交对数据库的影响是永久的

可重复读是怎么解决脏读

创建线程的方式

继承Thread类创建线程类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。

定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

mysql中整形数据类型
int。bigint。tunyint

如何强制使用某个索引?

针对salaries表emp_no字段创建索引idx_emp_no,查询emp_no为10005, 使用强制索引。
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
create index idx_emp_no on salaries(emp_no);
SELECT *
FROM salaries FORCE INDEX idx_emp_no
WHERE emp_no=10005
SELECT *
FROM salaries INDEXED BY idx_emp_no
WHERE emp_no=10005

分库分表怎么设计

大数据量并且访问频繁的表,将其分为若干个表:

答:根据海外国家拆分,分区表

将单一数据库的数据拆分到多个数据库中,以及如何将大数据量的表拆分到多张小表的过程,对于前者的拆分我们称之为数据库的垂直拆分,而后者我们称之为水平分割
垂直拆分:根据业务纬度
水平拆分:根据分片算法拆分,方法:1、按照哈希切片  2、按照时间切片

数据存储引擎有哪些
答:常见存储算法结构涵盖:哈希存储,B 、B+、B*树存储,LSM树存储引擎,R树,倒排索引,矩阵存储,对象与块,图结构存储等等。

索引使用b+树
 
2022年4月20日 07:29


mybatis(优秀的持久层框架,内部封装了jdbc)优点
:Mybatis是通过xml或注解的⽅式将需要执⾏的各种statement配置起来。通过Java对象和statement中的sql动态参数映射⽣成最终执⾏的sql语句,最终由Mabtais框架执⾏sql 并将结果映射为Java对象并返回

1、把sql 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写,给程序的维护带来了很大便利。
2、MyBatis 封装了底层 JDBC API 的调用细节,并能自动将结果集转换成 Java Bean 对象, 大大简化了 Java 数据库编程的重复工作。
3、因为 MyBatis 需要程序员自己去编写 sql 语句,程序员可以结合数据库自身的特点灵活控制 sql 语句,因此能够实现比 Hibernate 等全自动 orm 框架更高的查询效率,能够完成复杂查询。

mybatis的配置文件推荐为命名mybatis-config.xml,包含别名标签 事务管理 数据库用户名密码

mybatis映射文件

映射配置文件里的参数信息如下:
    •    parameterType(输入类型) 可输入的类型有三种:简单类型、pojo对象、pojo包装对象
    •    
    •    resultType(输出类型)
    •    可输出的类型有四种:返回一般数据类型(单条)、JavaBean 类型(单条)、List类型(多条)、Map类型
    •    
    •    resultMap(映射实体类)

mybatis分页
mybatis分页可以减少数据的处理量,分页的方式有两种:limit分页、PageHelper分页插件
limit(0,1)什么意思?

SELECT*FROM test LIMIT 0,10;#0是开始记录效,10是每页条数

int和bigint区别 bigint字节长度
主要有int,bigint,smallint和tinyint。其中比较迷惑的是int和smallint的差别。今天就在网上仔细找了找,找到如下内容,留档做个总结:
使用整数数据的精确数字数据类型。
bigint
从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字)。存储大小为 8 个字节。
P.S. bigint已经有长度了,在mysql建表中的length,只是用于显示的位数

int
从 -2^31 (-2,147,483,648) 到 2^31 – 1 (2,147,483,647) 的整型数据(所有数字)。存储大小为 4 个字节。int 的 SQL-92 同义字为 integer。一个字节8bite
smallint
从 -2^15 (-32,768) 到 2^15 – 1 (32,767) 的整型数据。存储大小为 2 个字节。
tinyint
从 0 到 255 的整型数据。存储大小为 1 字节。
注意:
int(M) 在 integer 数据类型中,M 表示最大显示宽度。在 int(M) 中,M 的值跟 int(M) 所占多少存储空间并无任何关系。和数字位数也无关系 int(3)、int(4)、int(8) 在磁盘上都是占用 4 btyes 的存储空间。

1char和varchar区别
1、最大长度:
char最大长度是255字符,varchar最大长度是65535个字节。
2、定长:
char是定长的,不足的部分用隐藏空格填充,varchar是不定长的。
3、空间使用:
char会浪费空间,varchar会更加节省空间。
4、查找效率:
char查找效率会很高,varchar查找效率会更低。
5、尾部空格:
char插入时可省略,vaechar插入时不会省略,查找时省略。

我们平时使用char类型定义字段时,往往会指定其长度M,即char(M)。其实M指的是字符数,即这个字段最多存储多少个字符,M可不指定,默认为1,范围是[0,255],单个字母、数字、中文等都是占用一个字符。utf8字符集下一个中文字符占用3个字节

varchar(M)中的的M表示保存的最大字符数,单个字母、数字、中文等都是占用一个字符。varchar可存储的长度范围为0-65535字节,此外,varchar需要使用1或者2个额外字节记录字符串的长度:如果列的最大长度小于或等于255字节,则只使用1个字节表示,否则使用2个字节。对于Innodb引擎,utf8字符集来说,单个中文字符占用3个字节,所以varchar(M)中的M最大不会超过21845,即M的范围是[0,21845),并且M必须指定。

CHAR类型是定长的,MySQL总是根据定义的字符串长度分配足够的空间。当保存CHAR值时,在它们的右边填充空格以达到指定的长度,当检索到CHAR值时,尾部的空格被删除掉。

VARCHAR类型用于存储可变长字符串,存储时,如果字符没有达到定义的位数,也不会在后面补空格。但是,由于行是变长的,在UPDATE时可能使行变得比原来更长,这就导致需要做额外的工作。如果一个行占用的空间增长,并且在页内没有更多的空间可以存储,在这种情况下InnoDB需要分裂页来使行可以放进页内,这样会增加碎片。

下面简单总结下CHAR与VARCHAR字段类型的适用场景:

CHAR适合存储很短的字符串,或者所有值都接近同一个长度。例如,CHAR非常适合存储密码的MD5值,因为这是一个定长的值。对于经常变更的数据,CHAR也比VARCHAR更好,因为定长的CHAR类型不容易产生碎片。对于非常短的列,CHAR比VARCHAR在存储空间上也更有效率。例如用CHAR(1)来存储只有Y和N的值,如果采用单字节字符集只需要一个字节,但是VARCHAR(1)却需要两个字节,因为还有一个记录长度的额外字节。

下面这些情况下使用VARCHAR是合适的:字符串很长或者所要存储的字符串长短不一,差别很大;字符串列的最大长度比平均长度大得多;列的更新很少,所以碎片不是问题。

面试题 float f=3.4是否正确?
答:不正确。正确float f =(float)3.4
第一数字常量包含小数点或者带F/D则为浮点数,第二浮点数常量是double型的,除非用字母f说明它是float型的,第三double不能自动转换为float,应改为float f =(float)3.4

Java⼋⼤数据类型:
(1)整数类型:byte、short、int、long
(2)⼩数类型:float、double
(3)字符类型:char
(4)布尔类型:boolean
学习内容:
1、 整数数据类型
byte:1个字节,8位,256种状态,取值范围为【-128,127】
short:2个字节,16位,65536种状态,取值范围为【-32768,32767】
int:4个字节,32位,整数类型默认是int类型,取值范围约21亿
long:8个字节,64位,long类型表⽰long类型常量,要加L或者l,建议加L,可以排序
2、 ⼩数数据类型
float:4个字节,32位,单精度,能精确到6~7位,声明⼀个⼩数类型,要加F或者f,建议加F
double:8个字节,64位,双精度,能精确到15~16位,⼩数类型默认是double类型
3、 字符数据类型
char:2个字节,16位,字符表⽰Unicode(万国码)编码表中的每⼀个符号,每个符号使⽤单引号引起来,其中前128个符号和ASCII表相同
4、 布尔数据类型
boolean:占1位,有true和false2个值,⼀个表⽰真,⼀个表⽰假,⼀般⽤于表⽰逻辑运算

mysql中int和integer区别为:类型不同、默认值不同、存储不同。
一、类型不同
1、int:在mysql中,int的数据类型是基本数据类型,是对integer的拆箱。
2、integer:在mysql中,integer的数据类型是引用数据类型,是对int的装箱。
二、默认值不同
1、int:在设置字段类型为int类型时,字段的默认值是0。
2、integer:在设置字段类型为integer类型时,字段的默认值是null。

三、存储不同
1、int:int是作为对象,直接存储数值。
2、integer:integer需要实例化对象,实际上是生成一个指针指向对象的地址。


poi
知识点
    ◦    EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。
    ◦    流:
    ◦    poi 处理xls poi-ooml处理xlsx

06-02索引在什么情况下会失效
答:
1.条件中有or,例如select * from table_name where a = 1 or b = 3
2.在索引上进行计算会导致索引失效,例如select * from table_name where a + 1 = 2
3. 在索引的类型上进行数据类型的隐形转换,会导致索引失效,例如字符串一定要加引号,假设 select * from table_name where a = '1'会使用到索引,如果写成select * from table_name where a = 1则会导致索引失效
4.使用函数会导致索引失效
5.使用like查询以%开头会导致索引失效
6. 使用!、=、<>等判断会导致索引失效

如何对索引进行优化
答:1:表记录太少或者经常增删的表或字段或者过滤/区别性不大的字段(如性别)不需要加索引
2:讲区分度较高的索引放在前面
3.尽量不使用select *
4.查询时索引字段参与运算会使索引失效

    ◦    为什么不用hashmap做索引
索引的本质是数据结构;因为hashmap无序;hash值在数量大的时候会冲突;


java异常面试题


    ◦    一个对象只有是throwable的实例,它才是异常类,Error很少出现,只需关注Exception下的类
    ◦    Java如何⾃定义异常?
⾃定义异常类只需从Exception类或者它的⼦类派⽣⼀个⼦类即可。⾃定义异常类如果继承Exception类,则为受检查异常,必须对其进⾏处理;如果不想处理,可以让⾃定义异常类继承运⾏时异常RuntimeException类。
    ◦    运行时异常(也叫非检查异常)包括空指针,indexoutofboundsexception,因为这类异常不影响编译所以不要求捕获或者抛出声明
    ◦    非运行时异常(也叫检查异常可理解为可遇见的异常)java编译器强制必须捕获处理,比如IOexception或Filenotfoundexception


面试题:你们的异常处理是运行时异常还是非异常?
答:继承exception,即受检查异常,(非运行时异常)都要处理,try catch 或者往上抛throws

异常不处理往外抛,抛到最外后程序会终止
正常应该是捕获异常,然后记录日志,不应该由于异常数据而影响下面正常数据处理

vue


关联查询最好不超过几张表 3

mysql优化  in 和 exist区别
wher in ()一个字段匹配多个值的时候使用
where exist (查询sql):如果查询sql有结果就返回true,没结果false,一般多表查询


springboot的创建bean的原理javabean的配置原理
    •    
    •    @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
    •    Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
    •    当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显示指定名称,@Resource可以通过 name 属性来显示指定名称。

spring的ioc和aop
ioc(控制反转)实现的方式有依赖注入,就是A类需要B类的对象,一般的方法是new个B类,利用IOC就只需要定义一个私有的B的成员变量,容器运行时会自动创建一个B类对象并将引用自动注入给成员变量
    1.    依赖注入的实现方法:构造方法注入,setter方法注入
    2.    依赖注入的相关注解:@autowired 自动按类型注入 @Resource直接按照bean的id注入,只能注入bean类型@Value注入基本数据类型和String类型
    3.    如何通过注解创建 Bean?
         @Component 把当前类对象存入Spring 容器中,相当于在 xml 中配置一个 bean 标签。value 属性指定bean 的id,默认使用当前类的首字母小写的类名。@Controller,@Service, @Repository 三个注解都是 @Component 的衍生注解,作用及属性都是檬一样的,只是提供了更加明确语义,@Controller 用于表现层,@Service用于业务层,@Repository用于持久层。如果注解中有且只有一个 value 属佳要赋值时可以省路 value。
4.如何通过注解配置文件?
@Confiquration用于指定当前类是-
一个springl配置类,当创建容器时会从该类上加载注解,value属性用于指定配置类的字节码

5.BeanFactory、FactoryBean 和 ApplicationContext 的区别?

BeanFactory 是一个 Bean工厂,使用简单工厂模式,是Sprina loC 容器顶级接口,可以理解为含有Bean 集合的工厂类,作用是管理 Bean,包括实例化、定位、配置对象及建立这些对象间的依赖
BeanFactory 实例化后并不会自动实例化 Bean,只有当 Bean 被使用时才实例化与装配依赖关系,属于延迟加载,适合多例模式。
    FactoryBean 是一个工厂Bean,使用了工厂方法模式,作用是生产其他 Bean 实例,可以通过实现该接口,提供一个工厂方法来自定义实例化 Bean 的设辑。FactoryBean 接口由 BeanFactory 中配置的对象实现,这些对象本身就是用于创建对象的工厂,如果-
- 个Bean 实现了这个接口,那么它就是创建
对象的工厂 Bean,而不是 Bean 实例本身
     ApplicationConext 是 BeanFactory 的子接口,扩展了 BeanFactory 的功能,提供了支持国际化的文本消息,统一的资源文件读取方式,事件传插以及应用层的特别配置等。容器会在初始化时对配置的
Bean 进行预实例化,Bean 的依赖注入在容器初始化时就已经完成,厲于立即加载,适合单例模式一般推荐使用。

AOP是什么?
    1.    aop是面向切面编程,就是将代码中重复的部分抽取出来
    2.    spring根据类是否实现接口来判断动态代理方式
    3.    常见场景包括权限认证自动缓存日志
    4.    @Aspect注解 声明被注解的类是一个切面bean
    1.    其中aspectjrt 的jar包中提供了我们编写切片过程中所需要的 @Pointcut,@After,@Aspect,@Before,@Around等注解。

定时任务框架
    ◦    通过数据库表t_taskinfo配置定时任务各种参数(包括定时任务名,定时任务类名,运行标识,运行时间
    ◦    可指定ip运行定时任务
    ◦    t_taskassign定时任务机器运行分配表,不管是单机还是多机,都得这个表添加完记录才能跑,相当于锁,(参数包括微服务名称,任务名称,运行任务ip,任务状态
    ◦    单个定时任务执行流程:设置当前运行时间和下次运行时间,分配定时任务运行权限,运行定时任务主逻辑,判断是否超时
    ◦    最简单的3种实现方法
    1.    Timer

  // 定义一个任务
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("Run timerTask:" + new Date());
            }
        };
        // 计时器
        Timer timer = new Timer();
        // 添加执行任务(延迟 1s 执行,每 3s 执行一次)
        timer.schedule(timerTask, 1000, 3000);

Timer 类实现定时任务的优点是方便,因为它是 JDK 自定的定时任务,但缺点是任务如果执行时间太长或者是任务执行异常,会影响其他任务调度,所以在生产环境下建议谨慎使用

2. ScheduledExecutorService
ScheduledExecutorService 可以实现 Timer 类具备的所有功能,并且它可以解决了 Timer 类存在的所有问题

class MyScheduledExecutorService {
    public static void main(String[] args) {
        // 创建任务队列
        ScheduledExecutorService scheduledExecutorService =
                Executors.newScheduledThreadPool(10); // 10 为线程数量
  // 执行任务
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            System.out.println("Run Schedule:" + new Date());
        }, 1, 3, TimeUnit.SECONDS); // 1s 后开始执行,每 3s 执行一次
    }

ScheduledExecutorService 小结

在单机生产环境下建议使用 

3.Spring Task
使用上面两种定时任务的实现方式,很难实现设定了具体时间的定时任务,比如当我们需要每周五来执行某项任务时,但如果使用 Spring Task 就可轻松的实现此需求。

以 Spring Boot 为例,实现定时任务只需两步
a 开启定时任务
@SpringBootApplication
@EnableScheduling // 开启定时任务
public class DemoApplication {
    // do someing
}

b 添加定时任务

定时任务的添加只需要使用 @Scheduled 注解标注即可,如果有多个定时任务可以创建多个 @Scheduled 注解标注的方法,示例代码如下:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
@Component // 把此类托管给 Spring,不能省略
public class TaskUtils {
    // 添加定时任务
    @Scheduled(cron = "59 59 23 0 0 5") // cron 表达式,每周五 23:59:59 执行
    public void doTask(){
        System.out.println("我是定时任务~");
    }
}
注意:定时任务是自动触发的无需手动干预,也就是说 Spring Boot 启动后会自动加载并执行定时任务。

注意:定时任务是自动触发的无需手动干预,也就是说 Spring Boot 启动后会自动加载并执行定时任务。

知识扩展:分布式定时任务

上面的方法都是关于单机定时任务的实现,如果是分布式环境可以使用 Redis 来实现定时任务。
使用 Redis 实现延迟任务的方法大体可分为两类:通过 ZSet 的方式和键空间通知的方式。
① ZSet 实现方式

通过 ZSet 实现定时任务的思路是,将定时任务存放到 ZSet 集合中,并且将过期时间存储到 ZSet 的 Score 字段中,然后通过一个无线循环来判断当前时间内是否有需要执行的定时任务,如果有则进行执行

java中public default protected privatr区别?

对象初始化顺序

static变量……non-static变量……构造函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值