JAVA面试汇总总结更新中ing

基础

1.面向对象的三个特征

封装,继承,多态,有时候也会加上抽象。

2.多态的好处

允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。主要有以下优点:
可替换性:多态对已存在代码具有可替换性
可扩充性:增加新的子类不影响已经存在的类结构
接口性:多态是超类通过方法签名,向子类提供一个公共接口,由子类来完善或者重写它来实现的。
灵活性
简化性

3.代码中如何实现多态

实现多态主要有以下三种方式:

  1. 接口实现
  2. 继承父类重写方法
  3. 同一类中进行方法重载

4.接口和抽象类的区别

比较抽象类接口
默认方法抽象类可以有默认的方法实现java 8之前,接口中不存在方法的实现.
实现方式子类使用extends关键字来继承抽象类.如果子类不是抽象类,子类需要提供抽象类中所声明方法的实现.子类使用implements来实现接口,需要提供接口中所有声明的实现.
构造器抽象类中可以有构造器接口中不能
和正常类区别抽象类不能被实例化接口则是完全不同的类型
访问修饰符抽象方法可以有public,protected和default等修饰接口默认是public,不能使用其他修饰符
多继承一个子类只能存在一个父类一个子类可以存在多个接口
添加新方法想抽象类中添加新方法,可以提供默认的实现,因此可以不修改子类现有的代码如果往接口中添加新方法,则子类中需要实现该方法.

5.父类的静态方法能否被子类重写

不能。重写只适用于实例方法,不能用于静态方法,而子类当中含有和父类相同签名的静态方法,我们一般称之为隐藏。

6.什么是不可变对象

不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。

7.静态变量和实例变量的区别?

静态变量存储在方法区,属于类所有。实例变量存储在堆当中,其引用存在当前线程栈。

8.java 创建对象的几种方式

采用new
通过反射
采用clone
通过序列化机制
前2者都需要显式地调用构造方法。造成耦合性最高的恰好是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用。

9.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4请问s5==s2返回什么?

返回false。在编译过程中,编译器会将s2直接优化为”ab”,会将其放置在常量池当中,s5则是被创建在堆区,相当于s5=new String(“ab”);

10.java中==和eqauls()的区别,equals()和`hashcode的区别

== 是运算符,用于比较两个变量是否相等,而equals是Object类的方法,用于比较两个对象是否相等。默认Object类的equals方法是比较两个对象的地址,此时和 == 的结果一样。换句话说:基本类型比较用==,比较的是他们的值。默认下,对象用==比较时,比较的是内存地址,如果需要比较对象内容,需要重写equal方法

11.equals()和hashcode()的联系

hashCode()是Object类的一个方法,返回一个哈希值。如果两个对象根据equal()方法比较相等,那么调用这两个对象中任意一个对象的hashCode()方法必须产生相同的哈希值。
如果两个对象根据eqaul()方法比较不相等,那么产生的哈希值不一定相等(碰撞的情况下还是会相等的。)

12.a==b与a.equals(b)有什么区别

如果a 和b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以通常需要重写该方法来提供逻辑一致性的比较。例如,String 类重写 equals() 方法,所以可以用于两个不同对象,但是包含的字母相同的比较。

13.3*0.1==0.3返回值是什么

false,因为有些浮点数不能完全精确的表示出来。

14.a=a+b与a+=b有什么区别吗?

+=操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换。

15.& 和 &&的区别

&是位操作,而&&是逻辑运算符。另外需要记住逻辑运算符具有短路特性,而&不具备短路特性。

16.String、StringBuilder、StringBuffer的区别及使用场景

String一旦定义就不可改变,可空赋值。操作少量数据时使用。
StringBuilder 可改变,线程不安全。操作单线程大量数据时使用。
StringBuffer 可改变,线程安全。操作多线程大量数据时使用

17.ArrayList、Vector和LinkedList的区别及使用场景

ArrayList和Vector都是使用数组方式存储数据,允许按序号索引元素,但是插入数据会涉及到元素移动等内存操作,所以索引快插入慢。
ArrayList懒加载 默认大小10 每次扩容1.5倍 线程不安全 性能较高
Vector 实例化时初始化 默认大小10 每次扩容2倍 线程安全 性能较低 已弃用
LinkedList 使用双向链表方式存储数据,插入只需要记录本项的前后项,索引需要向前或向后进行遍历,所以插入速度较快,线程不安全,频繁在任意位置插入和删除的情况可以使用,如果需要多线程访问,可以使用Connections.synchronizedList()或ConcurrentLinkedQueue


多读少写建议使用CopyOnWriteArrayList
CopyOnWriteArrayList原理是发生修改的时候复制一份
多写少读或读写比较均匀建议使用Connections.synchronizedList

18.List和Map的区别

List是存储单列数据的集合,Map是存储键值对双列数据的集合。
List存储的数据是有顺序且可重复的,Map存储的数据是无顺序,键不可重复,值可重复的。

19.HashMap和HashTable的区别

HashMap是Map接口的实现,非线程安全,允许空键值。
HashTable是Dictionary的子类,线程安全,不允许空键值。几乎被淘汰,建议使用ConcurrentHashMap来替代它。
HashMap使用的是快速失败迭代器,在迭代器创建后,除非通过迭代器自身的remove或者add方法,其他任何方式的修改都会抛出异常。

19.HashMap底层实现原理和扩容机制

JDK1.8以前:数组+单链表的组合,以键值对的方式存储元素。
DK1.8及以后:引入红黑树结构,添加元素时,若链表个数大于8,链表会转换为红黑树,反之小于6时会修剪或还原成链表结构。选择6和8可以有效防止频繁的链表和红黑树转换。
扩容条件:
1.存放新值的时候当前已有元素个数大于阈值。
2.存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值换算出来的数组下标位置已经存在值)
默认容量是16,负载因子0.75,所以扩容阈值是12。
每次扩容的容量是原有的2倍。

20.sleep()和wait()的区别

sleep()是Thread类的,wait()是Object类的方法
sleep不会释放锁,wait会释放锁。
sleep可在任意地方使用,wait notify notifyAll只能在synchronized块\方法中使用。
sleep必须捕获异常,而wait不需要。

21.抽象类和接口的区别、以及使用场景

1.抽象类中可以有构造方法、静态方法、普通方法、普通成员变量。接口中不能有。
2.抽象类中的抽象方法访问类型可以是public、protected和默认类型,接口中只能是public。
3.抽象类中的静态成员变量访问类型可以任意,接口中只能是public的。
4.一个类只能继承一个类,但是可以实现多个接口。
5.抽象类和子类为“是不是”的关系。主要用于为一些类提供公共实现代码。
6.接口和实现为“有没有”的关系。主要用于代码的扩展性和可维护性。

22.Overload(重载)和Override(重写)的区别

重载是一个类中多态性的一种表现,在一个类中定义了多个同名的方法,他们有不同的参数列表。
重写是父类与子类之间多态的一种表现,子类中定义了与父类有相同名称和参数的方法时,子类对象使用该方法会调用子类中的定义。

23.forward(转发)和redirect(重定向)的区别

forward是服务器请求资源,服务器访问目标URL,把响应内容发给用户,用户不知道数据是从哪来的。
redirect是服务器向客户端发送一个状态码,告知重新请求该URL。

24.什么是序列化

序列化就是一种用来处理对象流的机制,就是将对象的内容进行流化,可以对流化后的对象进行读写操作,也可以将流化后的对象传输于网络之间。
可通过实现java.io.Serializable接口来实现序列化。

25.说下HTTP和RPC的区别

分类RPCHTTP
通信方式是超文本传输协议,是一种客户端和服务器之间的请求-响应的模式,客户端发送请求,服务器返回响应,2者连接后立即断开是远程调用,是一种进程间的通信方式,双方建立连接以后,一个进程可以直接调用另一个进程的函数
传输协议i可以使用TCP和UTP为传输协议使用的是TCP协议作为传输协议
数据格式通常使用的是自定义的数据格式,比如JSON,XML等等使用的是标准的MIME类型,比如HTML,XML,JSON,图片等多种格式
连接方式双向通信期间会持续连接采用的是无连接的传输协议,每次连接只有立即断开,下次通信的时候需要重新建立连接
应用场景适用于内部系统集成,提供服务的调用和响应采适用于Web应用,网页访问和文件的传输

26.说说有哪些负载均衡算法

分类解释
轮询法将请求按照轮流的分配到后端的服务器,他均衡的对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载
随机法通过系统的随机算法,根据后端服务器的列表的大小值进行随机的选取其中一台服务器进行访问,由概率统计理论可以得知,随着客户端调用的服务端次数增多,其实际效果越来越接近平均调用量到每一台服务器上面,也是轮询的结果
源地址哈希法源地址哈希的思想是根据获取客户端的ip地址,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果辨识客户端要访问的服务器的序号,采用源地址哈希算法进行负载均衡,同一个IP的客户端,当后端服务器列表不变的时候后,他每次都会映射到同一台服务器上面进行访问
加权轮询法不同的后端服务器可能机器的配置和当前的系统负载并不相同,因此他们的抗压能力也不相同,给配置高的,负载低的服务器配置更高的权重,燃气在处理更多的请求,而配置低,负载高的机器给其降低权重,加权重的轮询可以很好的解决轮询法的弊端
加权随机法与加权轮询法一样,加权随机发也是根据后端机器的配置,系统的负载分配不同的权重,不同的是,他是按照权重随机请求后端服务器而非顺序

1.为什么CgLib可以代理任何类,但还是需要JDK的动态代理?CgLib和JDK动态代理的区别。

这就不得不说到CgLib的特点:创建速度慢但执行速度快,而JDK的动态代理与其刚好相反:创建速度快但执行速度慢。
如果在程序运行时不断地使用CgLib去创建代理的话,系统运行的性能会大打折扣,所以建议一般在系统初始化时采用CgLib来创建代理,并放入Spring的ApplicationContext中。

RocketMQ

1.RocketMQ怎么保证消息的有序性

答:
1.消息被发送时保持有序
2.消息被存储时保持和发送的顺序一致
3.消息被消费时保持和存储的顺序一致


实现方式可以是:
使用单线程+同步发送消息的形式来进行实现
简而言之:保证一个队列同一个时刻只能被一个消费者中一个线程消费


代码实现:
一.生产者
1.创建生产者
2.设置NameServer地址,如果是集群使用分号进行隔开
3.启动生产者
4.创建消息,并且制定主题和标签以及消息内容
5.实现MessageQueueSelector方法并且重写select方法,保证消息放在同一个队列(
第一个参数是,需要发送的消息
第二个参数是,消息队列选择器MessageQueueSelector
第三个参数是,消息需要进入的队列下标)
6.重写select方法里面
第一个参数是,指的是该主题下有的队列集合
第二个参数是,发送消息
第三个参数是,消息将要进入的队列下标
7.不在发送消息的时候关闭生产者实例


二.消费者
1.创建消费者
2.设置NameServer地址,如果是集群,使用分号隔开
3.设置消费者第一次启动是从队列头开始还是从队列后开始消费,如果不是第一次启动,那么按照上次消费的位置继续消费
4.订阅一个或者多个Topic,以及Tag来过滤需要消费的消息,如果订阅该主题下的所有tag,则使用*
5.与普通消费一样需要注册消息监听器,但是传入的不再是MessageListenerConcurrently,而是需要传入MessageListenerOrderly的实现子类,并重写consumeMessage方法。
6.顺序消费同一个队列的消息
7.标记该消息已经被成功消费
8.启动消费者实例

生产者

public class OrderMQProducer {
    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException, MQBrokerException, ExecutionException {
        // 创建DefaultMQProducer类并设定生产者名称
        DefaultMQProducer mqProducer = new DefaultMQProducer("producer-group-test");
        // 设置NameServer地址,如果是集群的话,使用分号;分隔开
        mqProducer.setNamesrvAddr("127.0.0.0:9876");
        // 启动消息生产者
        mqProducer.start();
        for (int i = 0; i < 5; i++) {
            // 创建消息,并指定Topic(主题),Tag(标签)和消息内容
            Message message = new Message("GLOBAL_ORDER_TOPIC", "", ("全局有序消息" + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
            // 实现MessageQueueSelector,重写select方法,保证消息都进入同一个队列
            // send方法的第一个参数: 需要发送的消息Message
            // send方法的第二个参数: 消息队列选择器MessageQueueSelector
            // send方法的第三个参数: 消息将要进入的队列下标,这里我们指定消息都发送到下标为1的队列
            SendResult sendResult = mqProducer.send(message, new MessageQueueSelector() {
                @Override
                // select方法第一个参数: 指该Topic下有的队列集合
                // 第二个参数: 发送的消息
                // 第三个参数: 消息将要进入的队列下标,它与send方法的第三个参数相同
                public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                    return mqs.get((Integer) arg);
                }
            }, 1);
            System.out.println("sendResult = " + sendResult);
        }
        // 如果不再发送消息,关闭Producer实例
        mqProducer.shutdown();
    }
}

消费者

public class OrderMQConsumer {
    public static void main(String[] args) throws MQClientException {
        // 创建DefaultMQPushConsumer类并设定消费者名称
        DefaultMQPushConsumer mqPushConsumer = new DefaultMQPushConsumer("consumer-group-test");
        // 设置NameServer地址,如果是集群的话,使用分号;分隔开
        mqPushConsumer.setNamesrvAddr("127.0.0.0:9876");
        // 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费
        // 如果不是第一次启动,那么按照上次消费的位置继续消费
        mqPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        // 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息,如果订阅该主题下的所有tag,则使用*
        mqPushConsumer.subscribe("GLOBAL_ORDER_TOPIC", "*");
        /**
         * 与普通消费一样需要注册消息监听器,但是传入的不再是MessageListenerConcurrently
         * 而是需要传入MessageListenerOrderly的实现子类,并重写consumeMessage方法。
         */
        // 顺序消费同一个队列的消息
        mqPushConsumer.registerMessageListener(new MessageListenerOrderly() {
            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                context.setAutoCommit(false);
                for (MessageExt msg : msgs) {
                    System.out.println("消费线程=" + Thread.currentThread().getName() +
                            ", queueId=" + msg.getQueueId() + ", 消息内容:" + new String(msg.getBody()));
                }
                // 标记该消息已经被成功消费
                return ConsumeOrderlyStatus.SUCCESS;
            }
        });
        // 启动消费者实例
        mqPushConsumer.start();
    }
}

2.使用RocketMQ如何快速处理积压消息

1.如果出现消息积压的问题,可以通过Consumer管理按钮实时看到消息的积压情况。
2.如果已经出现了消息积压的现象,如要快速的消费,可以在新建一个消费主题,将积压的老的消息进行消费掉
具体操作
1.准备一个临时的topic
2.queue的数量是堆积的几倍
3.queue分布到多Broker中
3.上线一台Consumer做消息的搬运工,把原来Topic中的消息挪到新的Topic里,不做业务逻辑处理,只是挪过去
4.上线N台Consumer同时消费临时Topic中的数据
5.改bug
6.恢复原来的Consumer,继续消费之前的Topic

3.为什么使用RocketMQ

因为项目比较大,做了分布式系统,所有远程服务调用请求都是同步执行经常出问题,所以引入了mq

作用描述
解耦系统耦合度降低,没有强依赖关系
异步不需要同步执行的远程调用可以有效提高响应时间
削峰请求达到峰值后,后端service还可以保持固定消费速率消费,不会被压垮

4.RocketMQ由哪些角色组成,每个角色作用和特点是什么

角色作用
Nameserver无状态,动态列表;这也是和zookeeper的重要区别之一。zookeeper是有状态的。
Producer消息生产者,负责发消息到Broker。
Broker就是MQ本身,负责收发消息、持久化消息等。
Consumer消息消费者,负责从Broker上拉取消息进行消费,消费完进行ack。

5.RocketMQ Broker中的消息被消费后会立即删除吗?

不会,每一条消息都会被持久化保存在commitlog中,每个Consumer连接到Broker后会维持消费进度信息,当有消息消费后只是当前Consumer的消费进度(CommitLog的offset)更新了。

6.消息重复消费怎么解决

原因:
1.正常情况下在consumer真正消费完消息后应该发送ack,通知broker该消息已正常消费,从queue中剔除
当ack因为网络原因无法发送到broker,broker会认为词条消息没有被消费,此后会开启消息重投机制把消息再次投递到consumer
2.在clustering模式下,消息在broker中会保证相同group的consumer消费一次,但是针对不同group的consumer会推送多次
处理:
1.处理消息前,使用消息主键在表中带有约束的字段中insert
2.单机时可以使用map ConcurrentHashMap -> putIfAbsent guava cache

7.RocketMQ如何保证消息不丢失

首先在如下三个部分都可能会出现丢失消息的情况:
Producer端
1.采取send()同步发消息,发送结果是同步感知的。
2.发送失败后可以重试,设置重试次数。默认3次。
producer.setRetryTimesWhenSendFailed(10);
Broker端
1.修改刷盘策略为同步刷盘。默认情况下是异步刷盘的。
flushDiskType = SYNC_FLUSH
Consumer端
1.完全消费正常后在进行手动ack确认。

8.那如果消息堆积时间过长消息超时了

RocketMQ中的消息只会在commitLog被删除的时候才会消失,不会超时。也就是说未被消费的消息不会存在超时删除这情况。

9.堆积的消息会不会进死信队列?

不会,消息在消费失败后会进入重试队列(%RETRY%+ConsumerGroup),16次(默认16次)才会进入死信队列(%DLQ%+ConsumerGroup)。

10.Broker把自己的信息注册到哪个NameServer上?

Broker会向所有的NameServer上注册自己的信息,而不是某一个,是每一个,全部!

11.cookie和session的区别

存储位置不同:cookie放在客户端电脑,session放在服务器端内存的一个对象
存储容量不同:cookie <=4KB,一个站点最多保存20个cookie,session是没有上限的,但是性能考虑不要放太多,而且要设置session删除机制
存储数据类型不同:cookie只能存储ASCll字符串,session可以存储任何类型的数据
隐私策略不同:cookie放在本地,别人可以解析,进行cookie欺骗,session放在服务器,不存在敏感信息泄露
有效期不同:可以设置cookie的过期时间,session依赖于jsessionID的cookie,默认时间为-1,只需要关闭窗口就会失效

12.jdk1.8的新特性

①lambda 表达式
②方法引用
③加入了base64的编码器和解码器
④函数式接口
⑤接口允许定义非抽象方法,使用default关键字即可
⑥时间日期类改进

13.什么是跨域?跨域的三要素

跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制协议、域名、端口
注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域

14.tomcat三个默认端口及其作用(不是重点问的特别少)

8005:这个端口负责监听关闭tomcat的请求。
8009:接受其他服务器的请求
8080:用于监听浏览器发送的请求

15.throw 和 throws 的区别?

throw:抛出一个异常。
throws:声明一个异常。

16.序列化和反序列化

序列化: 把对象转为字节序列的过程,在传递和保存对象时,保证了对象的完整性和可传递性,便于在网络传输和保存在本地文件中。
反序列化: 把字节序列转为对象的过程,通过字节流的状态和信息描述,来重建对象。
序列化特点:
将对象转为字节流存储到硬盘上,当JVM噶了的话,字节流还会在硬盘上等待,等待下一次JVM的启动,把序列化的对象,通过反序列化为原来的对象,减少储存空间和方便网络传输(因为是二进制)。

17.说说你对红黑树的理解

①根节点是黑色。
②节点是黑色或红色。
③每个红色节点的两个子节点都是黑色。
④红色节点的子节点都是黑色。
⑤从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

18.为什么链表长度大于8,并且表的长度大于64的时候,链表会转换成红黑树

因为链表长度越长,哈希冲突概率就越小,当链表等于8时,哈希冲突就非常低了,是千万分之一,我们的map也不会存那么多数据,如果真要存那么多数据,那就转为红黑树,提高查询和插入的效率。

19.为什么转成红黑树是8呢?而重新转为链表阈值是6呢?

因为如果都是8的话,那么会频繁转换,会浪费资源。

Spring

1.Spring Boot的核心注解是什么,它是由哪几个注解组成的

核心注解:@SpringBootApplication
包含:
@SpringBootConfiguration 实现配置文件功能
@EnableAutoConfiguration 打开自动配置功能
@CompoentScan 组件扫描功能

2.SpringBoot 怎么读取配置文件

属性上使用@Value注解
类上使用@ConfigurationProperties注解

3.SpringCloud和Dubbo的区别

SpringCloud采用基于HTTP的REST API,Dubbo采用RPC方式。

4.SpringCloud的Hystrix断路器特性

请求熔断:请求服务失败量超过一定比例(默认50%)断路器会切换到开路状态,这时所有请求不会发送到后端服务,断路器在保持开路状态一段时间后(默认5秒),自动切换到半开路状态。这时如果下一次请求成功,断路器切回闭路状态,否则重新切换到开路状态。
服务降级:对于查询操作,可以实现一个fallback方法。当请求服务出现异常时,可以使用fallback方法返回的值。
依赖隔离:通过线程池来实现资源隔离,比如一个服务调用另外两个服务,如果这两个服务在同一线程池,那么如果一个服务卡住,后面的请求又来了,就会导致后面的请求都会卡住等待。
请求缓存:缓存上次请求结果,返回给后续请求。
请求合并:把多个请求合并成一个请求,提升效率。

5.Mybatis中 #{} 和 ${}的区别

#{}是预编译,可防止SQL注入。
${}是直接拼接在SQL语句中。
30.浅拷贝和深拷贝的区别
浅拷贝: 基础数据类型复制值,引用类型复制引用地址,修改一个对象的值,另一个对象也随之改变。
深拷贝: 基础数据类型复制值,引用类型在新的内存空间复制值,新老对象不共享内存,修改一个值,不影响另一个。
深拷贝相对浅拷贝速度慢,开销大。

6.SpringBoot如何优化启动速度

1.删除一些没有必要的jar包依赖
2.添加配置,SpringBoot2.2版本后引入spring.main.lazy-initialization属性,配置为true会将所有Bean延迟初始化。
3.AOP切面尽量不使用注解方式,这会导致启动时扫描全部方法。
4.OpenFeign客户端接口的扫描缩小包扫描范围。

7.SpringBoot读取配置的几种方式

1.使用@value读取配置里面的属性值
2.使用@ConfigurationProperties并且制定对应的加载配置项的前缀,使用这个注解的是有需要再启动项上面添加@EnableConfigurationProperties(value=xxxxProperties.class)注解来进行启动注解的自动装配功能
3.使用@PropertySource注解,加载配置文件,然后再字段上使用@Value获取配置
4.

8.怎么解决SpringBoot的跨域请求

答:
首先需要先说说跨域的三要素,协议,域名,端口
我们通常是可以使用nginx来进行解决跨域的问题的

9.单例Bean是单例模式

答:
一般来说单例模式是指再一个jvm,一个类只能被构造出来一个对象,有很多方法来实现单例模式,比如懒汉模式,但是我们通常来说的单例模式是有一个前提条件的就是规定再一个jvm中,name如果是有2个jvm中保证单例吗,那可能就需要分布式锁这些技术了,这里的重点就是再讨论再单例模式的时候需要考虑到他的范围
然而再Spring中的单例Bean也是一种单例模式,只不过范围比较小,范围就是beanName,beanName对应同一个Bean对象,不同的beanName可以对应不同的Bean对象(就算是在一个类里面也是可以的)
比如我现在创建一个对象

@Component
public class TestBean{

}

这是一个TeatBean对象
下面我通过Bean注解来进行定义

public TeatBean teatBean1{
return new TeatBean();
}
public TeatBean teatBean2{
return new TeatBean();
}
public static void main (String[] args){
       AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
         System.out.println(annotationConfigApplicationContext.getBean("testBean"));
         System.out.println(annotationConfigApplicationContext.getBean("testBean1"));
         System.out.println(annotationConfigApplicationContext.getBean("testBean2"));

}

10.Bean的实例化和Bean的初始化有什么区别

Spring再创建Bean对象的时候,会先来创建一个java对象,会通过反射来执行类的构造方法从而得到一个java对象,而这个过程就是Bean的实例化
得到java对象以后,会进行依赖注入,依赖注入以后就会进行初始化的操作,而Bean的初始化就是调用前面创建出来的java对象中的特定方法,比如java对象实现了InitializingBean接口,那么初始化的时候就会执行java对象的afterPropertiesSet(),Spring只会执行这个方法,并不关心方法里面做了那些,我们可以再这个方法中去对某个属性进行验证,或者直接给某个属性进行赋值都可以,反而Bean的初始化就是执行afterPropertiesSet()方法,或者执行init-method指定的方法

11.Spring AOP是如何实现的?

Spring Aop是利用动态代理的机制,如果一个Bean实现了接口,那么就会采用jdk动态代理生成该接口的代理对象,如果一个Bean没有实现接口,那么就会采用CGLIB来生成当前类的一个代理对象,代理对象的作用就是代理原本的Bean对象,代理对象在执行某个方法,会在该方法的基础上增加一些切面的逻辑,使得我们可以利用AOP来实现一些诸如登录校验,权限控制,日志记录等统一功能

12.Spring中的事务是如何实现的?

Spring的事务底层使用的是AOP机制进行实现的
首先对于使用了@Transaction注解的Bean,Spring会创建一个代理对象作为Bean
当调用代理对象方法的时候,会判断该方法上是否添加了这个事务注解
如果进行添加了,那么就会利用事务管理器区创建一个数据库的连接
并且进行修改数据库连接的autocommit属性为false,禁止此链接的自动提交,这是实现Spring事务非常关键的一步
然后执行当前方法,方法回执行sql
执行完成方法以后,如果没有出现异常就会直接进行提交事务,如果是出现了异常就会进行事务的回滚操作
Spring事务的给你级别对象的就是数据库事务的隔离级别
Spring的事务传播机制指的就是和数据库进行的连接
Spring的事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开一个事务,那么实际上也就是新开一个和数据库的连接,再此连接上执行对应的sql

13.你是如何理解Spring事务的传播机制的,底层是如何实现的

答:
Spring的事务传播机制大白话解释就是有7种
1.当前有事务就加入,当前没有事务就新建
2.当前存在事务就加入,当前没有事务就报错
3.当前有事务就加入,当前没有事务就按照没有事务的形式执行
4.当前有事务就挂起重新创建一个事务,当前没有事务,重新创建一个事务
5.当前有事务就挂起,当前没有事务就按照没有事务进行执行
6.当前有事务就报错,当前没有事务就按照没有事务的方式进行执行
7.当前有是事务那么就在这个事务里面再嵌套一个事务进行执行,当前没有事务就新建一个事务
实际上Spring的事务就是一个Spring的事务对应的一个数据库的连接,新开一个事务就是新开一个和数据库的连接

14.那些情况下会导致Spring事务失效的,对应而定原因是什么

答:
1.方法内进行自调用:Spring事务是基于Aop的,只要会用代理对象调用某个方法的时候,Spring事务才会进行生效,而在一个方法中调用使用this.xxx()调用方法的时候,this并不是指的代理对象,所以就会导致事务的失效
解决方法就是把调用的方法拆分到另一个Bean中
或者自己注入自己
2.方法是使用的非Public的时候也是会导致事务的失效,因为Spring事务会基于Cglib来进行Aop的,而CGLIB会基于父子类来进行生效的,子类是代理类,父类是被代理类,如果父类中的某一个方法是私有的方法的时候,那么子类就没有办法重写他,也就没有办法额外的增加Spring事务的逻辑
3.方法使用final的时候或者static的时候也是不能进行重写他的,也就是会导致事务的失效
4.方法再执行的时候被trycatch的时候也是会导致事务的失效原因是事务无法进行捕获,也就是导致事务无法进行回滚
5.类没有交给Spring进行管理的时候事务也是会失效的
6.数据库不支持的事务

15.Spring 中的Bean创建的生命周期有哪些

答:
Spring中的Bean的生命周期简单的分为7步
1.推断构造方法–比如再有参和无参的构造方法中会优先使用无参的构造方法,如果没有但是有多个有参的构造方法,再这个情况下如果没有进行声明使用哪个就会报错,例如可以使用@Autoware的注解进行
2.实例化
3.填充属性,依赖注入
4.处理Aware回调
5.初始化前,处理@PostConstruct注解
6.初始化,处理InitilizingBean接口
7.初始化后,进行Aop

16.Spring中Bean是线程安全的吗

答:
Spring的Bean是不是线程安全的主要是看当前的Bean有没有状态,如果是有状态的那么就是线程安全的没有就是线程不安全的
那么什么是有状态什么是无状态了
有状态简单的来说就是具有存储数据的Bean
无状态指的是没有实例变量的对象,不能保存数据是不变的类
还有就是Spring的Bean是不是线程安全的和他的作用域是无关的,Bean的作用域只是代表的是Bean的生命周期对于任何生命周期的Bean都是一个对象,这个对象是不是线程安全的主要还是看这个Bean对象的本身

17.Spring中的启动流程是怎样的

答:
在创建Spring容器的时候也就是Spring启动的时候
首先会进行扫描,扫描到到的所有的BeanDefinition(BeanDefinition指的就是对应Bean的定义)对象,并存再一个Map中
然后筛选出非懒加载的单例BeanDefinition进行创建Bean,对于多例Bean不需要再启动过程中进行创建,对于多例Bean会在每次获取Bean的时候利用BeanDefinition去进行创建
利用BeanDefinition创建Bean也就是Bean的创建生命周期,这期间包括了合并BeanDefinition,推断构造方法,实例化,属性填充,初始化前,初始化,初始化后等操作,其中Aop就是发生再初始化后这一步骤中的
单例Bean创建完成以后,Spring就会发布一个容器启动事件
Spring启动结束
再源码中会更加的复杂,比如源码中会提供一些模板方法,让子类进行时间,比如源码中还会涉及到一些BeanFactoryPostProcessor和BeanPostProcessor的注册,Spring的扫描就是通过BeanFactoryPostProcessor来进行实现的,依赖注入就是通过BeanPostProcessor来实现的
在Spring启动的过程中还会区处理@Import等注解

18.SpringBootApplication注解有什么用?为什么一定要用它?

SpringBootApplication这个注解相当于是三个注解组成的分别是:
@SpringBootConfiguration(他其实就是相当于是@Configuration,表示当前是一个配置类)
@ComponenScan(Spring会进行扫描,扫描路径为当前再解析的这个类所在的包路径)
@EnableAutoConfiguration(这个注解会负责进行自动装配类的导入,也就是将项目中的自动装配类导入到Spring容器中,从而得到解析)
所以再使用SpringBoot的时候我们一般都是会加上@SpringBootApplication这个注解就是SpringBoot就会进行扫描,就会导入自动配置类并且进行解析

19.spring的bean生命周期

答:
bean的生命周期分为五个阶段
1.实例化bean
2.bean赋值
3.初始化bean
4.使用bean
5.销毁bean

20.谈谈对AOP的理解

答:
Aop指的是面向切面编程.首先是实现逻辑
第一步:创建切面类
第二步:在切面类里面定义切入点引用
第三步:书写通知
然后就是里面的通知是分为5种
1.前置通知
2.后置通知
3.异常通知
4.环绕通知
5.当前方法返回结果后通知
优点:
1.提高了代码的可用性
2.提高了代码的维护性高效
3.业务功能的拓展更加的方便
4.合理使用会使代码更加的简洁
缺点:
1.代码的可读性导致增强类的代码可读性不强,容易忽视切面类的存在
2.由于AOP代理,底层是使用到了反射的机制,从某种程度上来说也是增加了GC的工作量.

说到代理又得说到2个东西
1.静态代理
2.动态代理
首先静态代理就是自己创建代理类生成源代码再对其进行编译,再程序运行前代理类的.class文件就已经存在了,
至于动态代理就是在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术
这里的动态代理有2中
1.JDK动态代理
2.CGLIB动态代理

21.什么是IOC

答:
首先IOC指的是控制反转,就是我们创建bean资源交给spring来进行管理叫做ioc,然后再使用资源进行注入使用的是有叫做DI(依赖注入)

22.spring的事务在那些情况下会失效

答:
1.spring事务会在除了使用公共的public的方法上使用的时候会失效
2.如果方法是被fina或者staticl进行修饰的时候也是导致事务的失效的,原因是事务使用的是动态代理进行实现的如果使用了final进行修饰的时候就会导致事务里面的动态代理无法进行重写导致事务的失效
3.如果被try catch捕获或者报错被抛出的时候也是会导致事务的失效的’’
4. 多线程调用的时候也是会导致事务的失效,原因是spring的事务是和数据库进行连接的,同一个事务只能使用同一个数据库的连接,再多线程的场景下拿到的数据库的连接是不一样的所以不支持事务
5.使用了错误的传播行为例如Propagation.NOT_SUPPORTED也是不支持事务的
6.使用的是不支持事务的存储引擎,例如使用的是mysql的MyISAM
7.数据源没有进行配置事务管理器-----但是springboot框架里面使用的是默认开启了事务
8.调用的是本类的方法也是会导致事务的失效,主要是因为spring的事务是通过aop进行实现的,调用的本类的方法实际上是没有走代理的,所以无法进行增强也就是无法使用事务
9.service没有托管给spring也就是不是spring的bean所以也是会导致事务的失效

23.spring/springboot的常用注解有哪些

答:
@Controller/@Service/@Component/@Repository/@SpringBootApplication/@Configuration/@Value/@Order/@Autowired/@Bean/@ComponentScan/@Transactional/@ServletComponentScan

登录

1.你知道什么是单点登录吗?

单点登录(SSO:Single Sign On): 同一账号在多系统中,只登录一次,就可以访问其他系统。多个系统,统一登录。
列如:在一个公司下,有多个系统,比如淘宝和天猫,你登录上淘宝,就不用再去登录天猫了。
① Cookie: 用cookie为媒介,存放用户凭证。登录上父应用,返回一个加密的cookie,访问子应用的时候,会对cookie解密校验,通过就可以登录。不安全和不能跨域免登。
分布式session实现: 用户第一次登录,会把用户信息记录下来,写入session,再次登录查看session是否含有对应信息。session系统不共享,使用缓存等方式来解决。
③重定向: 父应用提供一个GET方式的登录接口A,用户通过子应用重定向连接的方式访问这个接口,如果用户还没有登录,则返回一个登录页面,用户输入账号密码进行登录,如果用户已经登录了,则生成加密的token,并且重定向到子应用提供的验证token的接口B,通过解密和校验之后,子应用登录当前用户,虽然解决了安全和跨域,但是没前两种简单。

技能操作

1.如何防止表单提交

①js屏蔽提交按钮。
②给数据库添加唯一约束。
③利用Session防止表单重复提交。会有一个token标记,表单提交的时候拦截器会检查是否一致,不一致就不通过。
④使用AOP切入实现。自定义注解,然后新增切入点,然后每次都记录过期时间,然后做比较。

线程

1.什么是进程? 线程是什么?多线程是什么?

进程:
是操作系统进行资源分配的最小单位。


线程:
在一个进程中,每个独立的功能都需要独立的去运行,这时又需要把当前这个进程划分成多个运行区域,每个独立的小区域(小单元)称为一个线程。


多线程:
一个进程如果只有一条执行任务,则称为单线程程序。
一个进程如果有多条执行任务,也就是说在一个进程中,同时开启多个线程,让多个线程同时去完成某些任务(功能)。则称为多线程程序。

2.守护线程和用户线程

守护线程: jvm给的线程。比如:GC守护线程。
用户线程: 用户自己定义的线程。比如:main()线程。
Thread.setDaemon(false)设置为用户线程
Thread.setDaemon(true)设置为守护线程

3.线程的各个状态

新建(New): 新建一个线程。
就绪(Runnable): 抢夺cpu的使用权。
运行(Running): 开始执行任务。
阻塞(Blocked): 让线程等待,等待结束进入就绪队列。
死亡(Dead): 线程正常结束或异常结束。

4.为什么 wait()、notify()、notifyAll()方法定义在 Object 类里面,而不是 Thread 类?

① 锁可以是任何对象,如果在Thread类中,那只能是Thread类的对象才能调用上面的方法了。
② java中进入临界区(同步代码块或同步方法),线程只需要拿到锁就行,而并不关心锁被那个线程持有。
③ 上面方法是java两个线程之间的通信机制,如果不能通过类似synchronized这样的Java关键字来实现这种机制,那么Object类中就是定义它们最好的地方,以此来使任何Java对象都可以拥有实现线程通信机制的能力。

5.start()和run()的区别

start()方法: 是启动线程,调用了之后线程会进入就绪状态,一旦拿到cpu使用权就开始执行run()方法,不能重复调用start(),否则会报异常。
run()方法: 就相当于一个普通的方法而已。直接调用run()方法就还只有一个主线程,还是会顺序执行,也可以重复调用run()方法。

6.实现多线程的方式

①继承Thread类。
②实现Runnable接口
③实现Callable接口
④线程池

7.Runnable和Callable的区别

①Runnable没有返回值,Callable有返回值。
②Runnable只能抛出异常,不能捕获,Callable 能抛出异常,也能捕获。

8.线程池的七大参数

corePoolSize: 核心线程数,创建不能被回收,可以设置被回收。
maximumPoolSize: 最大线程数。
keepAliveTime: 空闲线程存活时间。
unit: 单位。
workQueue: 等待队列。
threadFactory: 线程工程,用于创建线程。
handler: 拒绝策略。

9.启动线程为什么是运行star()方法而不是run()方法

如果直接调用run方法的时候,他只是作为一个普通方法进行执行
线程的运行状态
新建
就绪
阻塞
等待
终止

10.守护线程了解吗

我:不了解
面试官:好回去等通知吧
我:了解了解我说
我:嗯~
我:守护线程是一个特殊类型的线程,它是一种在后台提供服务的线程,主要用于其他线程提供支持和服务的,当所有的非守护线程都结束的时候,守护线程才会结束
比如垃圾回收GC就是守护进程
在有些任务再程序运行的后台执行,而不是需要与主线程同步,比如日志的记录垃圾回收,定时任务等等都可以使用守护线程
或者当所有的非守护线程都结束的时候,守护线程自动终止了,这个服务器端应用再所有的客户端都断开的时候,守护线程可以自动的关闭服务
守护线程还可以用于资源管理,比如数据库连接池中的线程池管理器可以使用守护线程来进行监控空闲的连接并且进行回收
守护线程的存在可以减少程序的资源的消耗他可以随着程序的结束而自动终止,

事务

1.事务的隔离级别

答:
1.读已提交-----读取其他事务已经提交的数据
2.读未提交-----读取其他事务还未提交的数据–可能出现脏读
3.可重复读-----同一个事务多次读取同一个数据,尽可能的保证数据的一致性但是可能出现幻读
4.串行读------确保每个事务读取的都是最新的数据,但是他的并发是最低的

2.事务的传播行为有哪些

答:
REQUIRED(有就加入,没有就开):如果当前没有事务,就会新建一个事务,如果当前已经存在一个事务就会加入到这个事务中,这个是默认的事务传播机制
SUPPORTS(有就加入,没有就不开):如果当前存在事务,则会加入事务,如果当前没有事务则是以非事务的方式继续进行
MANDATORY(有就加入,没有就抛出异常):如果当前存在事务,则会加入事务,如果当前没有事务则抛出异常
REQUIRES_NEW(必须开启一个事务,不管有没有都会开一个新的事务):表示创建一个新的事务,如果对当前存在事务,则把当前的事务挂起,也就是说不管外部方法是否开启事务,这里的内部方法都是会开启新的事务,并且开启的事务之间都是相互独立的互不干扰
NOT_SUPPORTED(有就挂起):以非事务进行运行,如果当前存在事务就将当前的事务进行挂起
NEVER(有就抛出异常):以非事务进行运行,如果当前存在事务则会抛出异常
NESTED:嵌套事务,如果调用方法已经有了一个事务,那么当前的方法将会嵌套再该事务中执行,如果当前调用的方法没有事务,那么当前的方法将会开启一个新的事务

15.GC的理解以及怎么进行处理

答:
GC指的就是jvm的垃圾回收
GC中有关于四种引用:
1.强引用-------不会被回收
2.软引用------内存足够的情况下是不回收的,之后再不够的时候才会进行回收
3.弱引用------有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象
4.顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收

16.什么是雪花算法

答:
雪花算法实际上是有64位组成第一位是默认的占位符,后面的41位是时间戳在后面的10位空间和机器编号,再后面的就是序列号进行组成,这样的算法是mybatis-plus里面就已经集成了这个算法,在需要这个算法的字段上添加注解属性为@TableId(value=“id” ,type=IdType.ID_WORKER)

17.什么是单点登录

答:

18.谈谈乐观锁和悲观锁的理解

答:
乐观锁:
指的是在操作数据的时候非常乐观,认为别人不会同时修改数据,因此乐观锁是不会上锁的,只是在执行更新的时候判断一下再次期间别人是否修改了数据,如果修改了数据规则,则放弃本次唱操作,否则继续执行操作
悲观锁:
指的是在操作数据的时候非常悲观,认为别人会同时修改数据,因此再操作数据的时候就会直接将数据锁住,知道操作完成才会释放锁,上锁期间其他人不能修改数据
其中synchronized和lock的实现都是悲观锁
乐观锁的实现方式:
1.CAS机制和版本号控制
需要读写的内存位置(V)
进行比较的预期值(A)
拟写入的新值(B)
CAS操作逻辑如下:如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。
版本控制:
版本号机制的基本思路是在数据中增加一个字段version,表示该数据的版本号,每当数据被修改,版本号加1。当某个线程查询数据时,将该数据的版本号一起查出来;当该线程更新数据时,判断当前版本号与之前读取的版本号是否一致,如果一致才进行操作。需要注意的是,这里使用了版本号作为判断数据变化的标记,实际上可以根据实际情况选用其他能够标记数据版本的字段,如时间戳等

19.mysql数据怎么恢复

答:
1.物理恢复,再mysql版本一致的情况下,将需要恢复的mysql的data目录下面的文件copy到目标的data目录下面
物理恢复需要注意设置权限的问题
2.使用navicat进行恢复-----需要先进行备份
首先先来查看一下当前的mysql的日志
show master status
3.基于时间点恢复
mysqlbinlog --start-datetime=“2024-02-01 21:00:00” --stop-datetime=“2024-02-01 21:05:00” --verbose binlog.000078
4.基于日志位置恢复
恢复所有的事务,直到给出停止位置为止
mysqlbinlog --stop-position=368312 binlog.000078 | mysql -u root -p
从给定的开始位置恢复所有的事务,直到二进制结束为止
mysqlbinlog --start-position=368312 binlog.000078 | mysql -u root -p

20.mysql里面的三种删除,并且有什么区别

类型解释执行速度
delete删除过程是每次从表中删除一行,并把该行删除操作作为事务记录在日志中保存
truncate表示删除表中所有数据,DDL操作是隐性提交的!不能rollback较快
dropdrop 属于数据库定义语言DDL,表示删除表, 也可以用来删除数据库,删除表格中的索引非常快

在使用drop 和truncate 请先备份数据

21.什么是红黑树,简述

答:

22.简述ThreadLoad

答:
ThreadLoad是java中所提供的的线程本地存储机制,可以使用这个机制将数据缓存再某个线程内部,这个线程可以再任意时刻,任意方法中获取缓存的数据
那么Threadlocal是怎么做到线程之间的一个相互隔离:
Threadlocal在使用set方法的时候会将自己Threadlocal和对应的值给到ThreadlocalMap交给他进行管理Threadlocal作为键value作为值进行存储起来,总的来说就是threadlocal的底层是通过ThreadlocalMap来进行实现的,每个thread对象中都会存在一个ThreadlocalMap,map的key为Threadlocal对象,map的value为需要缓存的值
那么threadlocal在使用的过程中需要注意哪些事项:
1.如果在线程池中使用Threadlocal会造成内存泄露,因为当Threadlocal对象使用完之后,应该要把设置的key,value也就是Entry对象进行回收,但是线程池中的线程不会回收,而线程对象是通过强引用指向ThreadlocalMap,ThreadlocalMap也是通过强引用指向Entry对象,线程不被回收,从而出现内存泄露,解决方案就是在使用Threadlocal对象以后,手动的调用Threadlocal的remove方法,手动的清除Entry对象
应用场景:
当一个共享变量是共享的时候,但是有需要每个线程互相不影响,相互隔离,就可以使用Threadlocal
比如我们再传递当前用户的时候使用Threadlocal设置当前登录人以及获取当前登录人
还有就是再使用一些线程不安全的工具对象的时候,比如SimpleDateFormat日期解析的时候可以把这个放在Threadlocal里面进行解析获取

23.redis的雪崩/击穿/穿透

答:
1.redis雪崩表示的是在某一段时间,缓存集中失效,导致全部走数据库,有可能会导致的数据库瘫痪服务器崩溃
解决方法:
1.设置redis数据的有效时间永不过期,但是这个方法需要根据具体的业务逻辑来,一般是建议这样使用
2.设置redis的失效时间比较分散,比如设置某一个失效时间是随机的,
3.如果是出现redis宕机了,可以使用熔断降级机制,防止直接访问数据库,直接返回错误
1.redis缓存穿透指的是大致可以理解为现在在客户端有大量的请求访问redis以及数据库没有的数据,导致数据库的压力巨大
解决方法:
1.再接口层进行校验比如用户鉴权校验以及对应的数据进行校验添加上规则不符合规则无法进行访问
2.或者设置无效的数据比如键值对key-value设置为null并且有效时间为短时间值为null
1.redis击穿指的是
比如现在项目有某个热点数据,但是这个热点数据被大量的进行访问并且过期了,这个时候数据被大量的进行请求访问
解决方法:
1.设置热点数据的有效时间及时更新,再要过期的时候进行设置时候重新设置有效时间,或者设置永久

24.创建线程的有几种方式

答:创建线程有三种方式
1.Thread继承重写run方法
2.实现Runnable接口
3.实现Callable接口,这个是能带有返回值的

25.线程池有哪几种状态,每种状态有是代表什么

答:
分为运行状态-------关闭状态/停止状态-------整理状态--------终止状态
首先是running运行状态指的是:线程池创建或者调用的excute()方法后,处于运行状态,能够接收新的任务
关闭状态:当线程池调用shutdown方法的时候就会变为关闭状态,当前的线程池就不能再去接收新的任务,但是可以继续执行已经提交等待的任务队列的任务
停止状态:指的是当前线程池调用shutdownNow()方法的时候,线程池的状态就会变为shop状态,此时线程不在接收新的任务进来并且也不会再去执行其他的再队列中的任务,只会执行当前正在执行的任务
整理状态:中间状态不做任何的处理
终止状态:线程池内部的所有线程都已经全部终止,线程进入终止状态

26.springboot解决跨域的几种方式

跨域异常是只有再前端的时候才会出现跨域异常
现在是前后端分离的,前端和后端使用的是不同的端口,那么就会出现跨域的异常
这里的跨域建议使用nginx请求

27.springboot获取配置的几种方式

1.通过再Bean类里面使用@Value注解来进行获取配置文件里面的值-----设置一个一个的值进行绑定
2.通过再@ConfigurationProperties(prefix=“wsw”),这个时候配置文件里面wsw子项的所有的属性全部加载下来

微服务

1.微服务有哪些好处

答:
首先微服务的好处就需要拿微服务和单体架构进行比较
先来说说单体架构的有哪些缺点
1.可拓展性受限:比如现在我有一个单体架构的项目里面有一个模块的并发量非常高,这个时候可能会使用到nginx的负载均衡进行处理但是一番这么做,我目前也就可能会将这个项目进行搭建集群的形式进行处理,这样就会导致资源的浪费
2.维护更新成本比较高:因为随着时间的推移可能单体应用程序有可能会出现需求的迭代更新,里面的业务逻辑和代码有可能会变得越来越复杂庞大,难以理解维护和更新了,
3.高风险:比如现在程序里面出现了一个小的错误有可能就对导致整个应用程序的崩溃,所以存在比较高的风险,还有就是如果长时间的不进行更新单体应用也会有可能出现安全的危险
4.技术栈受到限制:单体架构里面的技术栈大体都是差不多的,这就可能会导致再项目里面如果想要使用到新的技术栈的和工具的能力难以实现收到了限制
5.团队协作复杂:单体架构再团队协作开发的过程当中会比较麻烦,比如提交代码这块吧,有可能就会导致代码的提交冲突


那么现在就来说说微服务有哪些
好处:
1.可扩展性:微服务架构允许根据需要独立的扩展需要的单个服务,从而不比扩展这个应用程序,这就提高了可扩展性
2.灵活性和快速开发:微服务运行开发团队独立设计开发和部署服务,这就大大提高了灵活性允许团队更快的退出新的功能和更新新的功能
3.故障隔离和容错性:单个微服务如果出现了故障通常是不会导致整个项目之间崩溃的,提高了应用程序的容错性,这样也就可以对于每个服务更加方便的进行维护
4.技术方便基本不收到限制,比如现在有一个服务是java书写的,但是现在有一个开源而定框架使用的是.net进行书写的我也可以直接拿过来进行使用
5.每个人负责自己对应的服务,并且可以根据对应的人员能力负责对应的服务板块
缺点:
1.基础设施成本增加,因为微服务应用通常需要更多的资源和基础设施资源,例如服务器,容器管理负载均衡等等都会进行增加运营成本
2.开发和维护成本:管理多个微服务的开发,测试,部署和维护需要更多的工程师的资源,这就可能会导致开发和维护的成本的增加
3.分布式系统的复杂性:微服务应用是分布式的系统,涉及多个独立运行的服务,还增加了系统的复杂性质,包括网络通信,故障处理和事务管理等等方面
4.服务治理he发现:管理多个微服务的发现,注册,版本控制和路由需要额外的复杂性,例如使用服务网格和API网关
5.自动化部署的要求:为了有效的部署多个微服务,需要建立自动化部署的流程,这就需要额外的工作和资源
6.版本的控制和回滚:管理不同版本的微服务以及版本之间的兼容性可能会变得复杂,特别是在需要回滚的时候
7.数据的一致性:不同的微服务可能都是用有各自的数据存储的,确保数据一致性和同步可能需要复杂的解决方案,如分布式事务或时间驱动的一致性
8.事务管理:管理过多个微服务的事务变得复杂,确保事务的一致性和隔离性需要额外的努力和技术
9.性能监控:在微服务环境中,跟踪性能问题和故障排查可能也会变得更加的复杂,因为问题可能涉及到多个服务,需要强大的监控和诊断工具才可以
10.故障排查:需要有效的方法来跟踪和诊断多个服务的故障,以便快速的恢复

2.微服务有哪些组件

答:
实际上一般我们只需要回答出来5个就可以了针对SpringCloud来进行回答出来(注册中心/远程调用/网关/熔断器/负载均衡)
1.注册中心
用于服务的注册和发现,管理微服务的地址信息,常见的有Nacos/Eureka等等
2.远程调用
主要是用于不同微服务之间进行通信和协作,常见的实现有:Fegin/OpenFegin/RestTemplate/Dubbo(RPC的形式进行远程调用,效率是最高的)
3.API网关
网关主要是作为微服务架构的入口,统一暴露服务,并且提供路由负载均衡安全认证等等的功能常见的网关有:Zuul/Gateway(常用的)等
4.分布式事务
保证跨多个微服务的一致性和原子性的操作常见的有Seata
5.熔断器
主要是用于防止微服务之间的故障扩散,提高系统的容错能力和可用性,并且也可以针对微服务过载的时候进行限制和降级处理常见的有:Hystrix
6.分布式追踪和监控:
主要是用于跟踪和监控微服务的请求流程和性能指标常见的有:SpringCloud Sleuth +Zipkin/SkyWalking
7.负载均衡:用于在分布式系统中将请求分配给不同的服务器节点,以达到均衡负载、提高系统性能和可伸缩性的目的。以下是一些常见的负载均衡算法:

4.注册中心是用来做什么的

答:注册中心主要是用于维护管理分布式系统中各个服务的地址和元数据组件的.还有就是主要也是为了发现服务和注册服务的

5.有哪些注册中心,并且说明这些注册中心有哪些区别

6.为什么微服务需要配置中心

7.什么是分布式?和微服务有什么区别

8.什么是CAP定理?为什么三者不能同时拥有

9.BASE理论了解吗?

10.什么是分布式事务

11.分布式事务有哪些常见的实现方案

12.有哪些分布式锁的实现方案

13.说下seata的XA和AT原理

JVM

14.类的生命周期
1.JVM的类加载机制

2.jvm内存区域

3.对象创建过程了解吗

4.对象内存分配方式

5.jvm创建对象是如何解多线程内存抢占的

6.对象内存布局和大小计算

7.jvm内存泄露的原因

8.如何判断对象仍然存活

9.垃圾收集算法了解吗

10.三色标记算法了解吗,三色标记优点

11.说一下CMS收集器的垃圾回收过程

12.G1垃圾回收器了解吗

13.为什么还要引入G1

14.你们的项目用的是什么垃圾收集器,为什么使用他

15.对象一定分配再堆中吗

16.了解那些jvm监控和故障处理工具

17.jvm的常见参数配置知道那些

18.有做过jvm调优吗

19.线上服务cpu占用过高怎么排查

20.内存飙高问题怎么排查

21.频繁minor gc怎么办

22.频繁Full GC 怎么办

23.定位以及解决OOM

KAFKA

1.kafka消息丢失有几种情况?如何解决

消息发送端:
acks=0:表示发送端producer不需要等待任何broker确认收到消息的回复,可以继续发送下一条消息,性能最高,但是也是最容易导致消息的丢失情况,大数据统计报表场景,对于性能的要求很高,对于丢失数据并不是特别的敏感的情况下可以使用这种
acks=1:至少要等待leader(主节点)已经成功的将数据写入本地log,但是不需要等待所有的follower(从节点)是否写入成功,就可以就绪发送下一条消息,这种情况下,如果foller(从节点)没有成功备份数据,而此时leader(主节点)又挂掉了,消息就会丢失
acks=-1或者all的时候:这就意味着leader(主节点)需要等待所有的备份写入日志,这种策略会保证只要有一个备份存活就不会丢失数据这个也是最强的数据保证,一般除非是金融级别或者是和钱敏感数据打交道的场景才会使用这个配置,但是如果这里所有的备份只有一个的情况下和ack=1是一样的还是会丢失数据
消息消费端:
如果消费这边配置的是自动提交,玩意消费到的数据还没有处理完,就自动提交offset了但是此时你的消费consumer直接进行了宕机,未处理完的数据丢失了下次也是消费不到的了,所以再消费端可以设置手动提交

2.kafka消息重复消费有几种情况怎么解决

答:
消息发送端:
发送消息如果配置了重试机制,比如网络抖动的时间过长导致发送端发送超时时,实际broker可能已经接收到消息,但是发送方会重新的发送消息

消息接收端:如果消费这边的配置的是手动提交,刚拉取了一部分数据处理了一部分,但是还没有来得及提交,服务器挂了,下次重启优惠拉取相同的一批数据重复处理
一般消费端都是需要多消费幂等处理的

3.kafka线上消息积压如何解决

答:
1.线上有时因为发送方发送消息速度过快,或者消费方消费消息过慢,就会可能导致broker积压大量的未消费的消息
这种情况如果积压上百万消息需要紧急的进行处理,可以修改消费端程序,让其将接收到的消息快速的转发到其他的topic(可以设置很多个分区),然后再去启动多个消费者同时进行消费新的主题的不同的分区
2.由于消费数据格式变动或者消费者程序有bug,导致消费者一直消费不成功,也是会导致broker积压大量的未消费的消息,
这个情况该可以将这些消费不成功的消息转发到其他的队列里面去步入类似的死信队列中,后面再慢慢的分析私信队列里面的消息进行处理问题

MYSQL

1.事物的四大特性和隔离级别

原子性:不可分割的操作单元,要么全部成功,要么回滚。
一致性:如果执行事物之前数据库是一致的,那么执行后还是一致的。
隔离性:事物操作之间彼此独立和透明,互不影响。
持久性:事物一旦提交,其结果就是永久的。
未提交读:允许脏读,其他事物只要修改了数据,即使未提交,本事物也能看到修改后的数据值。
提交读:只能读取到已提交的数据。
可重复读(innoDB默认):无论其他事物是否修改并提交了数据,这个事物中的数据不受影响。
串行读:完全串行化的读,每次读都要获得锁,读写相互都会阻塞。

2.MySQL在哪些情况下不使用索引

like查询使用%开头不能使用索引,但用%结尾的可以使用索引。
where语句中使用<>或!=。
where语句中使用or,且没有把or中的所有字段加上索引。
where语句中对字段表达式操作。
where语句中使用NOT IN。使用简单的IN会使用索引。

3.MySQL分库分表策略

垂直切分:某个表字段过多,可以将不常用或字段长度较大的字段拆分出去到扩展表中。
水平切分:分为库内分表和分库分表,是根据表内数据的逻辑关系,按照不同的条件分散到多个数据库或表中。

4.mysql的底层使用的是什么数据结构

答:
使用的是B+Tree数据结构,并且再B+Tree的基础上加了优化添加了指针指向相邻的叶子结点的链表,这样就形成了带有顺序的指针的B+tree结构了,主要是为了提高区间访问的效率

5.我现在有一个表怎么查询去重

答:
例如现在有一张表A,里面有字段test1,test2,需要查询字段test1并且进行去重
方法1:如果在有索引的情况下可以使用这个
select distinct test1 from A;
方法二:
select test1 ,count(test1) from A where 1=1 group by test1 ;

6.索引有哪些,创建索引有哪些注意事项

唯一索引:
主键索引:
聚集索引:
普通索引:
全文索引:
字段具有唯一的性质的时候:常见唯一索引
字段频繁的被作为条件使用的时候可以添加索引
针对字段进行去重使用DISTINCT 的时候可以再这个列上添加索引
使用列的类型小的创建索引
使用率特别高的创建索引
数据量特别小的可以不需要创建索引,除非涉及到连表查询可以进行添加索引,使用2个有索引的键进行关联

7.索引在那些情况会失效

1.使用or关键字(但是并不是所有带or的查询都会失效,如果有两个字段,两个字段都有索引就不会失效,会走两个索引)
2.使用like关键字没有遵守最左匹配原则(但是并不是所有like查询都会失效,只有在查询时字段最左侧加%和左右侧都加%才会导致索引失效)
3.索引列有运算符!=
4.如果数据库觉得不走索引会查询的更快也会导致索引失效,比如再数据量特别少的时候,索引也是会失效的
5.索引列类型不匹配导致索引的失效,

8.事务的各个隔离级别是如何实现的

9.mysql的主从复制有了解吗

10.mysql主从同步延迟怎么处理

11.水平分表有哪几种路由方式

12.分库分表后如何实现不停机扩容

13.分库分表会带来什么问题

14.mysql数据库cpu飙升怎么解决

15.一条sql执行很慢,怎么进行优化

一.排查慢的原因
1、没有索引或者没有用到索引
2、I/O吞吐量小,形成了瓶颈效应。
3、没有创建计算列导致查询不优化。
4、内存不足
5、网络速度慢
6、查询出的数据量过大(可以采用多次查询,其他的方法降低数据量)
7、锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷)
8、sp_lock,sp_who,活动的用户查看,原因是读写竞争资源。
9、返回了不必要的行和列
10、查询语句不好,没有优化
二.对症下药
1、优化查询方法
1.1、升级硬件
1.2、根据查询条件,建立索引,优化索引、优化访问方式,限制结果集的数据量。注意填充因子要适当(最好是使用默认值0)。索引应该尽量小,使用字节数小的列建索引好(参照索引的创建),不要对有限的几个值的字段建单一索引如性别字段
1.3、把数据、日志、索引放到不同的I/O设备上,增加读取速度,以前可以将Tempdb应放在RAID0上,SQL2000不在支持。数据量(尺寸)越大,提高I/O越重要.
1.4纵向、横向分割表,减少表的尺寸(sp_spaceuse)
5、提高网速;

6、扩大服务器的内存,Windows 2000和SQL server 2000能支持4-8G的内存。配置虚拟内存:虚拟内存大小应基于计算机上并发运行的服务进行配置。运行 Microsoft SQL Server? 2000 时,可考虑将虚拟内存大小设置为计算机中安装的物理内存的 1.5 倍。如果另外安装了全文检索功能,并打算运行 Microsoft 搜索服务以便执行全文索引和查询,可考虑:将虚拟内存大小配置为至少是计算机中安装的物理内存的 3 倍。将 SQL Server max server memory 服务器配置选项配置为物理内存的 1.5 倍(虚拟内存大小设置的一半)。

7、增加服务器CPU个数;但是必须明白并行处理串行处理更需要资源例如内存。使用并行还是串行程是MsSQL自动评估选择的。单个任务分解成多个任务,就可以在处理器上运行。例如耽搁查询的排序、连接、扫描和GROUP BY字句同时执行,SQL SERVER根据系统的负载情况决定最优的并行等级,复杂的需要消耗大量的CPU的查询最适合并行处理。但是更新操作UPDATE,INSERT, DELETE还不能并行处理。

8、如果是使用like进行查询的话,简单的使用index是不行的,但是全文索引,耗空间。 like ‘a%’ 使用索引 like ‘%a’ 不使用索引用 like ‘%a%’ 查询时,查询耗时和字段值总长度成正比,所以不能用CHAR类型,而是VARCHAR。对于字段的值很长的建全文索引。

9、DB Server 和APPLication Server 分离;OLTP和OLAP分离

10、分布式分区视图可用于实现数据库服务器联合体。联合体是一组分开管理的服务器,但它们相互协作分担系统的处理负荷。这种通过分区数据形成数据库服务器联合体的机制能够扩大一组服务器,以支持大型的多层 Web 站点的处理需要。有关更多信息,参见设计联合数据库服务器。(参照SQL帮助文件’分区视图’)

a、在实现分区视图之前,必须先水平分区表
b、在创建成员表后,在每个成员服务器上定义一个分布式分区视图,并且每个视图具有相同的名称。这样,引用分布式分区视图名的查询可以在任何一个成员服务器上运行。系统操作如同每个成员服务器上都有一个原始表的复本一样,但其实每个服务器上只有一个成员表和一个分布式分区视图。数据的位置对应用程序是透明的。

11、重建索引 DBCC REINDEX ,DBCC INDEXDEFRAG,收缩数据和日志 DBCC SHRINKDB,DBCC SHRINKFILE. 设置自动收缩日志.对于大的数据库不要设置数据库自动增长,它会降低服务器的性能。 在T-sql的写法上有很大的讲究,下面列出常见的要点:首先,DBMS处理查询计划的过程是这样的:

1、 查询语句的词法、语法检查
2、 将语句提交给DBMS的查询优化器
3、 优化器做代数优化和存取路径的优化
4、 由预编译模块生成查询规划
5、 然后在合适的时间提交给系统处理执行
6、 最后将执行结果返回给用户其次,看一下SQL SERVER的数据存放的结构:一个页面的大小为8K(8060)字节,8个页面为一个盘区,按照B树存放。

12、Commit和rollback的区别 Rollback:回滚所有的事物。 Commit:提交当前的事物. 没有必要在动态SQL里写事物,如果要写请写在外面如: begin tran exec(@s) commit trans 或者将动态SQL 写成函数或者存储过程。

13、在查询Select语句中用Where字句限制返回的行数,避免表扫描,如果返回不必要的数据,浪费了服务器的I/O资源,加重了网络的负担降低性能。如果表很大,在表扫描的期间将表锁住,禁止其他的联接访问表,后果严重。

14、SQL的注释申明对执行没有任何影响

15、尽可能不使用光标,它占用大量的资源。如果需要row-by-row地执行,尽量采用非光标技术,如:在客户端循环,用临时表,Table变量,用子查询,用Case语句等等。游标可以按照它所支持的提取选项进行分类: 只进 必须按照从第一行到最后一行的顺序提取行。FETCH NEXT 是唯一允许的提取操作,也是默认方式。可滚动性 可以在游标中任何地方随机提取任意行。游标的技术在SQL2000下变得功能很强大,他的目的是支持循环。

有四个并发选项

READ_ONLY:不允许通过游标定位更新(Update),且在组成结果集的行中没有锁。
OPTIMISTIC WITH valueS:乐观并发控制是事务控制理论的一个标准部分。乐观并发控制用于这样的情形,即在打开游标及更新行的间隔中,只有很小的机会让第二个用户更新某一行。当某个游标以此选项打开时,没有锁控制其中的行,这将有助于最大化其处理能力。如果用户试图修改某一行,则此行的当前值会与最后一次提取此行时获取的值进行比较。如果任何值发生改变,则服务器就会知道其他人已更新了此行,并会返回一个错误。如果值是一样的,服务器就执行修改。 选择这个并发选项OPTIMISTIC WITH ROW VERSIONING:此乐观并发控制选项基于行版本控制。使用行版本控制,其中的表必须具有某种版本标识符,服务器可用它来确定该行在读入游标后是否有所更改。
在 SQL Server 中,这个性能由 timestamp 数据类型提供,它是一个二进制数字,表示数据库中更改的相对顺序。每个数据库都有一个全局当前时间戳值:@@DBTS。每次以任何方式更改带有 timestamp 列的行时,SQL Server 先在时间戳列中存储当前的 @@DBTS 值,然后增加 @@DBTS 的值。如果某 个表具有 timestamp 列,则时间戳会被记到行级。服务器就可以比较某行的当前时间戳值和上次提取时所存储的时间戳值,从而确定该行是否已更新。服务器不必比较所有列的值,只需比较 timestamp 列即可。如果应用程序对没有 timestamp 列的表要求基于行版本控制的乐观并发,则游标默认为基于数值的乐观并发控制。
SCROLL LOCKS 这个选项实现悲观并发控制。在悲观并发控制中,在把数据库的行读入游标结果集时,应用程序将试图锁定数据库行。在使用服务器游标时,将行读入游标时会在其上放置一个更新锁。如果在事务内打开游标,则该事务更新锁将一直保持到事务被提交或回滚;当提取下一行时,将除去游标锁。如果在事务外打开游标,则提取下一行时,锁就被丢弃。因此,每当用户需要完全的悲观并发控制时,游标都应在事务内打开。更新锁将阻止任何其它任务获取更新锁或排它锁,从而阻止其它任务更新该行。
然而,更新锁并不阻止共享锁,所以它不会阻止其它任务读取行,除非第二个任务也在要求带更新锁的读取。滚动锁根据在游标定义的 SELECT 语句中指定的锁提示,这些游标并发选项可以生成滚动锁。滚动锁在提取时在每行上获取,并保持到下次提取或者游标关闭,以先发生者为准。下次提取时,服务器为新提取中的行获取滚动锁,并释放上次提取中行的滚动锁。滚动锁独立于事务锁,并可以保持到一个提交或回滚操作之后。如果提交时关闭游标的选项为关,则 COMMIT 语句并不关闭任何打开的游标,而且滚动锁被保留到提交之后,以维护对所提取数据的隔离。所获取滚动锁的类型取决于游标并发选项和游标 SELECT 语句中的锁提示。
锁提示 只读 乐观数值 乐观行版本控制 锁定无提示 未锁定 未锁定 未锁定 更新 NOLOCK 未锁定 未锁定 未锁定 未锁定 HOLDLOCK 共享 共享 共享 更新 UPDLOCK 错误 更新 更新 更新 TABLOCKX 错误 未锁定 未锁定 更新其它 未锁定 未锁定 未锁定 更新 *指定 NOLOCK 提示将使指定了该提示的表在游标内是只读的。

16、用Profiler来跟踪查询,得到查询所需的时间,找出SQL的问题所在;用索引优化器优化索引

17、注意UNion和UNion all 的区别。UNION all好

18、注意使用DISTINCT,在没有必要时不要用,它同UNION一样会使查询变慢。重复的记录在查询里是没有问题的

19、查询时不要返回不需要的行、列

20、用sp_configure ‘query governor cost limit’或者SET QUERY_GOVERNOR_COST_LIMIT来限制查询消耗的资源。当评估查询消耗的资源超出限制时,服务器自动取消查询,在查询之前就扼杀掉。 SET LOCKTIME设置锁的时间

21、用select top 100 / 10 Percent 来限制用户返回的行数或者SET ROWCOUNT来限制操作的行

22、在SQL2000以前,一般不要用如下的字句: “IS NULL”, ” <> “, “!=”, “!> “, “! <“, “NOT”, “NOT EXISTS”, “NOT IN”, “NOT LIKE”, and “LIKE ‘%500′”,因为他们不走索引全是表扫描。也不要在WHere字句中的列名加函数,如Convert,substring等,如果必须用函数的时候,创建计算列再创建索引来替代.还可以变通写法:WHERE SUBSTRING(firstname,1,1) = ‘m’改为WHERE firstname like ‘m%’(索引扫描),一定要将函数和列名分开。并且索引不能建得太多和太大。NOT IN会多次扫描表,使用EXISTS、NOT EXISTS ,IN , LEFT OUTER JOIN 来替代,特别是左连接,而Exists比IN更快,最慢的是NOT操作.如果列的值含有空,以前它的索引不起作用,现在2000的优化器能够处理了。相同的是IS NULL,“NOT”, “NOT EXISTS”, “NOT IN”能优化她,而” <> ”等还是不能优化,用不到索引。

23、使用Query Analyzer,查看SQL语句的查询计划和评估分析是否是优化的SQL。一般的20%的代码占据了80%的资源,我们优化的重点是这些慢的地方。

24、如果使用了IN或者OR等时发现查询没有走索引,使用显示申明指定索引: SELECT * FROM PersonMember (INDEX = IX_Title) WHERE processid IN (‘男’,‘女’)

25、将需要查询的结果预先计算好放在表中,查询的时候再SELECT。这在SQL7.0以前是最重要的手段。例如医院的住院费计算。

26、MIN() 和 MAX()能使用到合适的索引

27、数据库有一个原则是代码离数据越近越好,所以优先选择Default,依次为Rules,Triggers, Constraint(约束如外健主健CheckUNIQUE……,数据类型的最大长度等等都是约束),Procedure.这样不仅维护工作小,编写程序质量高,并且执行的速度快。

28、如果要插入大的二进制值到Image列,使用存储过程,千万不要用内嵌INsert来插入(不知JAVA是否)。因为这样应用程序首先将二进制值转换成字符串(尺寸是它的两倍),服务器受到字符后又将他转换成二进制值.存储过程就没有这些动作: 方法:Create procedure p_insert as insert into table(Fimage) values (@image), 在前台调用这个存储过程传入二进制参数,这样处理速度明显改善。

29、Between在某些时候比IN速度更快,Between能够更快地根据索引找到范围。用查询优化器可见到差别。 select * from chineseresume where title in (‘男’,’女’) Select * from chineseresume where between ‘男’ and ‘女’ 是一样的。由于in会在比较多次,所以有时会慢些。

30、在必要是对全局或者局部临时表创建索引,有时能够提高速度,但不是一定会这样,因为索引也耗费大量的资源。他的创建同是实际表一样。

31、不要建没有作用的事物例如产生报表时,浪费资源。只有在必要使用事物时使用它。

32、用OR的字句可以分解成多个查询,并且通过UNION 连接多个查询。他们的速度只同是否使用索引有关,如果查询需要用到联合索引,用UNION all执行的效率更高.多个OR的字句没有用到索引,改写成UNION的形式再试图与索引匹配。一个关键的问题是否用到索引。

33、尽量少用视图,它的效率低。对视图操作比直接对表操作慢,可以用stored procedure来代替她。特别的是不要用视图嵌套,嵌套视图增加了寻找原始资料的难度。我们看视图的本质:它是存放在服务器上的被优化好了的已经产生了查询规划的SQL。对单个表检索数据时,不要使用指向多个表的视图,直接从表检索或者仅仅包含这个表的视图上读,否则增加了不必要的开销,查询受到干扰.为了加快视图的查询,MsSQL增加了视图索引的功能。

34、没有必要时不要用DISTINCT和ORDER BY,这些动作可以改在客户端执行。它们增加了额外的开销。这同UNION 和UNION ALL一样的道理。 SELECT top 20 ad.companyname,comid,position,ad.referenceid,worklocation, convert(varchar(10),ad.postDate,120) as postDate1,workyear,degreedescription FROM jobcn_query.dbo.COMPANYAD_query ad where referenceID in(‘JCNAD00329667′,’JCNAD132168′,’JCNAD00337748′,’JCNAD00338345′,’JCNAD00333138′,’JCNAD00303570′, ‘JCNAD00303569′,’JCNAD00303568′,’JCNAD00306698′,’JCNAD00231935′,’JCNAD00231933′,’JCNAD00254567′, ‘JCNAD00254585′,’JCNAD00254608′,’JCNAD00254607′,’JCNAD00258524′,’JCNAD00332133′,’JCNAD00268618′, ‘JCNAD00279196′,’JCNAD00268613′) order by postdate desc

35、在IN后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,减少判断的次数

36、当用SELECT INTO时,它会锁住系统表(sysobjects,sysindexes等等),阻塞其他的连接的存取。创建临时表时用显示申明语句,而不是 select INTO. drop table t_lxh begin tran select * into t_lxh from chineseresume where name = ‘XYZ’ –commit 在另一个连接中SELECT * from sysobjects可以看到 SELECT INTO 会锁住系统表,Create table 也会锁系统表(不管是临时表还是系统表)。所以千万不要在事物内使用它!!!这样的话如果是经常要用的临时表请使用实表,或者临时表变量。

37、一般在GROUP BY 个HAVING字句之前就能剔除多余的行,所以尽量不要用它们来做剔除行的工作。他们的执行顺序应该如下最优:select 的Where字句选择所有合适的行,Group By用来分组个统计行,Having字句用来剔除多余的分组。这样Group By 个Having的开销小,查询快.对于大的数据行进行分组和Having十分消耗资源。如果Group BY的目的不包括计算,只是分组,那么用Distinct更快

38、一次更新多条记录比分多次更新每次一条快,就是说批处理好

39、少用临时表,尽量用结果集和Table类性的变量来代替它,Table 类型的变量比临时表好

40、在SQL2000下,计算字段是可以索引的,需要满足的条件如下:

a、计算字段的表达是确定的
b、不能用在TEXT,Ntext,Image数据类型
c、必须配制如下选项 ANSI_NULLS = ON, ANSI_PADDINGS = ON, …….

41、尽量将数据的处理工作放在服务器上,减少网络的开销,如使用存储过程。存储过程是编译好、优化过、并且被组织到一个执行规划里、且存储在数据库中的 SQL语句,是控制流语言的**,速度当然快。反复执行的动态SQL,可以使用临时存储过程,该过程(临时表)被放在Tempdb中。以前由于SQL SERVER对复杂的数学计算不支持,所以不得不将这个工作放在其他的层上而增加网络的开销。SQL2000支持UDFs,现在支持复杂的数学计算,函数的返回值不要太大,这样的开销很大。用户自定义函数象光标一样执行的消耗大量的资源,如果返回大的结果采用存储过程

42、不要在一句话里再三的使用相同的函数,浪费资源,将结果放在变量里再调用更快

43、SELECT COUNT(*)的效率教低,尽量变通他的写法,而EXISTS快.同时请注意区别: select count(Field of null) from Table 和 select count(Field of NOT null) from Table 的返回值是不同的。

44、当服务器的内存够多时,配制线程数量 = 最大连接数+5,这样能发挥最大的效率;否则使用 配制线程数量 <最大连接数启用SQL SERVER的线程池来解决,如果还是数量 = 最大连接数+5,严重的损害服务器的性能。

45、按照一定的次序来访问你的表。如果你先锁住表A,再锁住表B,那么在所有的存储过程中都要按照这个顺序来锁定它们。如果你(不经意的)某个存储过程中先锁定表B,再锁定表A,这可能就会导致一个死锁。如果锁定顺序没有被预先详细的设计好,死锁很难被发现

46、通过SQL Server Performance Monitor监视相应硬件的负载 Memory: Page Faults / sec计数器如果该值偶尔走高,表明当时有线程竞争内存。如果持续很高,则内存可能是瓶颈。

1、% DPC Time 指在范例间隔期间处理器用在缓延程序调用(DPC)接收和提供服务的百分比。(DPC 正在运行的为比标准间隔优先权低的间隔)。 由于 DPC 是以特权模式执行的,DPC 时间的百分比为特权时间 百分比的一部分。这些时间单独计算并且不属于间隔计算总数的一部 分。这个总数显示了作为实例时间百分比的平均忙时。
2、%Processor Time计数器 如果该参数值持续超过95%,表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。
3、% Privileged Time 指非闲置处理器时间用于特权模式的百分比。(特权模式是为操作系统组件和操纵硬件驱动程序而设计的一种处理模式。它允许直接访问硬件和所有内存。另一种模式为用户模式,它是一种为应用程序、环境分系统和整数分系统设计的一种有限处理模式。操作系统将应用程序线程转换成特权模式以访问操作系统服务)。 特权时间的 % 包括为间断和 DPC 提供服务的时间。特权时间比率高可能是由于失败设备产生的大数量的间隔而引起的。这个计数器将平均忙时作为样本时间的一部分显示。
4、% User Time表示耗费CPU的数据库操作,如排序,执行aggregate functions等。如果该值很高,可考虑增加索引,尽量使用简单的表联接,水平分割大表格等方法来降低该值。 Physical Disk: Curretn Disk Queue Length计数器该值应不超过磁盘数的1.5~2倍。要提高性能,可增加磁盘。 SQLServer:Cache Hit Ratio计数器该值越高越好。如果持续低于80%,应考虑增加内存。 注意该参数值是从SQL Server启动后,就一直累加记数,所以运行经过一段时间后,该值将不能反映系统当前值。

47、分析select emp_name form employee where salary > 3000 在此语句中若salary是Float类型的,则优化器对其进行优化为Convert(float,3000),因为3000是个整数,我们应在编程时使用3000.0而不要等运行时让DBMS进行转化。同样字符和整型数据的转换。

48、查询的关联同写的顺序

select a.personMemberID, * from chineseresume a,personmember b where personMemberID
= b.referenceid and a.personMemberID = ‘JCNPRH39681’ (A = B ,B = ‘号码’)

select a.personMemberID, * from chineseresume a,personmember b where a.personMemberID
= b.referenceid and a.personMemberID = ‘JCNPRH39681’ and b.referenceid = ‘JCNPRH39681’ (A = B ,B = ‘号码’, A = ‘号码’)

select a.personMemberID, * from chineseresume a,personmember b where b.referenceid
= ‘JCNPRH39681’ and a.personMemberID = ‘JCNPRH39681’ (B = ‘号码’, A = ‘号码’)

(1)IF 没有输入负责人代码 THEN code1=0 code2=9999 ELSE code1=code2=负责人代码 END IF 执行SQL语句为: SELECT 负责人名 FROM P2000 WHERE 负责人代码>=:code1 AND负责人代码 <=:code2
(2)IF 没有输入负责人代码 THEN SELECT 负责人名 FROM P2000 ELSE code= 负责人代码 SELECT 负责人代码 FROM P2000 WHERE 负责人代码=:code END IF 第一种方法只用了一条SQL语句,第二种方法用了两条SQL语句。在没有输入负责人代码时,第二种方法显然比第一种方法执行效率高,因为它没有限制条件;在输入了负责人代码时,第二种方法仍然比第一种方法效率高,不仅是少了一个限制条件,还因相等运算是最快的查询运算。我们写程序不要怕麻烦

50、关于JOBCN现在查询分页的新方法(如下),用性能优化器分析性能的瓶颈,如果在I/O或者网络的速度上,如下的方法优化切实有效,如果在CPU或者内存上,用现在的方法更好。请区分如下的方法,说明索引越小越好。

begin
DECLARE @local_variable table (FID int identity(1,1),ReferenceID varchar(20))
insert into @local_variable (ReferenceID)
select top 100000 ReferenceID from chineseresume order by ReferenceID
select * from @local_variable where Fid > 40 and fid <= 60
end
 
和
 
begin
DECLARE @local_variable table (FID int identity(1,1),ReferenceID varchar(20))
insert into @local_variable (ReferenceID)
select top 100000 ReferenceID from chineseresume order by updatedate
select * from @local_variable where Fid > 40 and fid <= 60
end
 
的不同
 
begin
create table #temp (FID int identity(1,1),ReferenceID varchar(20))
insert into #temp (ReferenceID)
select top 100000 ReferenceID from chineseresume order by updatedate
select * from #temp where Fid > 40 and fid <= 60 drop table #temp
end

另附:存储过程编写经验和优化措施 From:网页教学网

一、适合读者对象:数据库开发程序员,数据库的数据量很多,涉及到对SP(存储过程)的优化的项目开发人员,对数据库有浓厚兴趣的人。

二、介绍:在数据库的开发过程中,经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。如果项目的SP较多,书写又没有一定的规范,将会影响以后的系统维护困难和大SP逻辑的难以理解,另外如果数据库的数据量大或者项目对SP的性能要求很,就会遇到优化的问题,否则速度有可能很慢,经过亲身经验,一个经过优化过的SP要比一个性能差的SP的效率甚至高几百倍。

三、内容:

1、开发人员如果用到其他库的Table或View,务必在当前库中建立View来实现跨库操作,最好不要直接使用“databse.dbo.table_name”,因为sp_depends不能显示出该SP所使用的跨库table或view,不方便校验。

2、开发人员在提交SP前,必须已经使用set showplanon分析过查询计划,做过自身的查询优化检查。

3、高程序运行效率,优化应用程序,在SP编写过程中应该注意以下几点:

a)SQL的使用规范:

i. 尽量避免大事务操作,慎用holdlock子句,提高系统并发能力。
ii. 尽量避免反复访问同一张或几张表,尤其是数据量较大的表,可以考虑先根据条件提取数据到临时表中,然后再做连接。
iii. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。
iv. 注意where字句写法,必须考虑语句顺序,应该根据索引顺序、范围大小来确定条件子句的前后顺序,尽可能的让字段顺序与索引顺序相一致,范围从大到小。
v. 不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
vi. 尽量使用exists代替selectcount(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用,而且count(1)比count(*)更有效率。
vii. 尽量使用“>=”,不要使用“>”。
viii. 注意一些or子句和union子句之间的替换
ix. 注意表之间连接的数据类型,避免不同类型数据之间的连接。
x. 注意存储过程中参数和数据类型的关系。
xi. 注意insert、update操作的数据量,防止与其他应用冲突。如果数据量超过200个数据页面(400k),那么系统将会进行锁升级,页级锁会升级成表级锁。

b)索引的使用规范:

i. 索引的创建要与应用结合考虑,建议大的OLTP表不要超过6个索引。
ii. 尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过indexindex_name来强制指定索引
iii. 避免对大表查询时进行tablescan,必要时考虑新建索引。
iv. 在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。
v. 要注意索引的维护,周期性重建索引,重新编译存储过程。
c)tempdb的使用规范:
i. 尽量避免使用distinct、order by、groupby、having、join、cumpute,因为这些语句会加重tempdb的负担。
ii. 避免频繁创建和删除临时表,减少系统表资源的消耗。
iii. 在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替createtable,避免log,提高速度;如果数据量不大,为了缓和系统表的资源,建议先createtable,然后insert。
iv. 如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。
v. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后droptable,这样可以避免系统表的较长时间锁定。
vi. 慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。

d)合理的算法使用:

根据上面已提到的SQL优化技术和ASETuning手册中的SQL优化内容,结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令:setstatistics io on, set statistics time on , set showplan on等。

最后1条

尽量用其它写法,取代NOT IN,如a,b表同结构,数据量很大,则代替select * from a where a.c not in (select c from b )

的语句有

a)select a.* from a, b where a.c = b.c + and b.c is null(据说速度比原写法提高30倍)
b)select * from a minus select a.* from a,b where a.c=b.c (速度其次)
c)select * from a where not exist(select a.* from a,b where a.c=b.c) (也不错)

一、操作符优化

1、IN 操作符

用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格。但是用IN的SQL性能总是比较低的,从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有以下区别:
ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。

推荐方案:在业务密集的SQL当中尽量不采用IN操作符,用EXISTS 方案代替。

2、NOT IN操作符

此操作是强列不推荐使用的,因为它不能应用表的索引。
推荐方案:用NOT EXISTS 方案代替

3、IS NULL 或IS NOT NULL操作(判断字段是否为空)
判断字段是否为空一般是不会应用索引的,因为索引是不索引空值的。

推荐方案:用其它相同功能的操作运算代替,如:a is not null 改为 a>0 或a>’’等。不允许字段为空,而用一个缺省值代替空值,如申请中状态字段不允许为空,缺省为申请。

4、> 及 < 操作符(大于或小于操作符)

大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有100万记录,一个数值型字段A,30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为A>2时ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到=3的记录索引。

5、LIKE操作符

LIKE操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。

一个实际例子:用YW_YHJBQK表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 则会利用YY_BH的索引进行两个范围的查询,性能肯定大大提高。

6、UNION操作符
UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。如:
select * from ***fys
union
select * from ls_jg_dfys

这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

推荐方案:采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。
select * from ***fys
union all
select * from ls_jg_dfys

二、SQL书写的影响

1、同一功能同一性能不同写法SQL的影响。

如一个SQL在A程序员写的为 Select * from zl_yhjbqk
B程序员写的为 Select * from dlyx.zl_yhjbqk(带表所有者的前缀)
C程序员写的为 Select * from DLYX.ZLYHJBQK(大写表名)
D程序员写的为 Select * from DLYX.ZLYHJBQK(中间多了空格)

以上四个SQL在ORACLE分析整理之后产生的结果及执行的时间是一样的,但是从ORACLE共享内存SGA的原理,可以得出ORACLE对每个SQL 都会对其进行一次分析,并且占用共享内存,如果将SQL的字符串及格式写得完全相同,则ORACLE只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析SQL的时间,而且可以减少共享内存重复的信息,ORACLE也可以准确统计SQL的执行频率。

2、WHERE后面的条件顺序影响

WHERE子句后面的条件顺序对大数据量表的查询会产生直接的影响。如:
Select * from zl_yhjbqk where dy_dj = ‘1KV以下’ and xh_bz=1
Select * from zl_yhjbqk where xh_bz=1 and dy_dj = ‘1KV以下’
以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj = ‘1KV以下’条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz的比较,以此可以得出第二条SQL的CPU占用率明显比第一条低。

3、查询表顺序的影响

在FROM后面的表中的列表顺序会对SQL执行性能影响,在没有索引及ORACLE没有对表进行统计分析的情况下,ORACLE会按表出现的顺序进行链接,由此可见表的顺序不对时会产生十分耗服物器资源的数据交叉。(注:如果对表进行了统计分析,ORACLE会自动先进小表的链接,再进行大表的链接)

三、SQL语句索引的利用

1、操作符优化(同上)

2、对条件字段的一些优化

采用函数处理的字段不能利用索引,如:
substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’
trunc(sk_rq)=trunc(sysdate), 优化处理:sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)
进行了显式或隐式的运算的字段不能进行索引,如:ss_df+20>50,优化处理:ss_df>30
‘X’ || hbs_bh>’X5400021452’,优化处理:hbs_bh>’5400021542’

sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5
hbs_bh=5401002554,优化处理:hbs_bh=’ 5401002554’,注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型。

条件内包括了多个本表的字段运算时不能进行索引,如:ys_df>cx_df,无法进行优化
qc_bh || kh_bh=’5400250000’,优化处理:qc_bh=’5400’ and kh_bh=’250000’

四、其他

ORACLE的提示功能是比较强的功能,也是比较复杂的应用,并且提示只是给ORACLE执行的一个建议,有时如果出于成本方面的考虑ORACLE也可能不会按提示进行。根据实践应用,一般不建议开发人员应用ORACLE提示,因为各个数据库及服务器性能情况不一样,很可能一个地方性能提升了,但另一个地方却下降了,ORACLE在SQL执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)、服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分析。

Redis

1.redis到底是单线程还是多线程

单线程,内部是多线程的计算方式

2.redis单线程为什么还能这么快

答:
1.命令执行是基于内存操作的
2.命令执行是单线程操作,没有线程切换的开销
3.基于IO多路复用机制提升redis的I/O利用率
4.高效的数据存储结构:全局hash表以及多钟高效的数据结构,比如:跳表,压缩列表,链表

3.redis底层数据是如何用跳表来存储的
在这里插入图片描述

答:
将有序链表改造为支持近似折半查找的算法,可以进行快速的插入,删除,查找等操作

4.redis key过期了为什么内存没释放

答:
1.本身我再设置数据的时候是设置了过期时间,但是再修改数据的时候没有设置过期时间,这样就会导致这个数据变为了没有过期时间的数据了
2.使用的redis的删除策略有关
定期删除和惰性删除
惰性删除:redis过期了,不执行删除等到下次访问的时候再去删除
定期删除:redis过期了,不执行删除,redis没有定期的(或者定期轮询)那些数据过期了,再去将这些数据删除

5.redis key没设置过期时间为什么被redis主动删除了

答:
redis设置了过期时间但是也是有可能会导致被主动的删除的
1.redis人为的操作进行删除的
2.redis的淘汰策略有关
1.如果redis里达到了设置内存的最大值,这个时候会执行淘汰删除,
扫描当前库使用频率最少的
扫描当前库使用次数最少的
扫描当前库即将过期的
扫描当前库,随机进行删除
放弃驱逐淘汰删除
全库扫描使用频率最少的
全库扫描使用次数最少的
全库进行随机删除

6.redis淘汰key的算法lru与lfu区别

答:
LRU:删除使用频率最少的或者说是已经很久没有使用的key
IFU:删除使用次数最少的或者说是删除最近一段时间方位次数最少的数据

7.删除key的命令会阻塞redis吗

答:
会造成阻塞的
原因是
1.redis是单线程的所以如果出现大量的key删除,但是处理不过来就有可能会造成redis的阻塞
2.value的值非常的大也是会造成阻塞比如value的值都是占用了几个G了
3.还有就是再再删除一些链表或者集合的时候也是会造成阻塞的,如果这个链表或者集合是非常复杂的情况下

8.redis主从,哨兵,集群架构优缺点比较

9.redis集群数据hash分片算法怎么回事

10.一次线上事故,redis主从切换导致了缓存雪崩

答:
尽可能的保证主从服务器的时钟的一致性,否在可能原先的主服务器还没有过期但是从服务器是已经过期了,这个时候在发生主从切换,就会导致这个问题的出现

11.redis线上数据如何备份

答:
1.写crontab定时调度脚本,每小时都copy一份rdb或者aof文件到另外一个机器上去,保存最近的48小的备份
2.每天都保留一份当日的数据备份到一个目录中去,可以保留最近一个月的备份
3.每次copy备份的时候,都把太旧的备份给删除了

12.线上redis持久化策略一般如何设置

答:
如果是对性能要求比较高的,再Master主最好不要做持久化,可以再某一个Slave开启AOP备份数据,策略设置为每秒同步一次即可

13.redis和数据库保证数据一致性

14.redis的数据类型有哪些

答:
String(字符串)
list(列表)
hash(哈希)
set(集合)
zset(有序集合)

15.redis的淘汰策略和删除策略

答:
删除策略:
定时删除(时间换空间)
创建一个定时器,当key设置了有过期时间,当过期时间到达的手定时器任务就会立即执行对键的删除操作
惰性删除(空间换时间)
数据到达过期时间,不做处理,等待下次访问数据的时候,我们需要判断
1).未过期,返回数据
2)过期了,删除数据,返回不存在
定期删除
就是周期性的轮询redis数据库中的失效性数据,采取随机抽取的策略,你利用过期数据占比的方式控制删除的频率
cpu性能的占用设置有峰值,检测频率可自定义的设置
内存压力不是很大,长期占用的内存的冷数据会被持续清理
周期性抽查存储空间(随机抽查,重点抽查)
淘汰策略:
1.易失数据
1.1.volatile-lru
挑选最近使用最少的数据淘汰
1.2volatile-lfu
挑选最近使用次数最少的数据进行
1.3volatile-ttl
挑选将要过期的数据进行淘汰
1.4volatile-random
任意选择数据进行淘汰
2.检测全库的数据
2.1allkeys-lru:挑选最近最少使用的数据淘汰
2.2allkeLyRs-lfu::挑选最近使用次数最少的数据淘汰
2.3allkeys-random:任意选择数据淘汰,相当于随机
3.放弃数据驱逐
3.1no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发OOM(Out Of Memory)

16.redis的持久化方式

持久化方式RDBAOF
占用存储空间小(数据级:压缩)大(指令级:重写)
存储速度
恢复速度
数据安全性会丢失数据依据策略决定
资源消耗高/重量级低/轻量级
启动优先级

答:
RDB持久化
数据采用数据集快照的形式进行部分持久化模式,记录数据库的所有的键值对,在某一个时间点将数据写入的临时文件,持久化结束以后用这个临时文件替换上一次持久化的文件从而达到数据而定恢复但是这个存在数据丢失的现象
AOP持久化
是将所有的命令记录以redis的命令请求格式进行完全的持久化存储保存为aof文件,读的操作不进行记录

17.redis的日志怎么看

答:
redis的日志是在redis-server.log

linux

8.linux常用指令有哪些

答:
cd
pwd---------查看当前路径
vim---------编辑
mkdir-------创建文件
ls/ll--------查看当前的文件有哪些
jps-------查看线程

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值