java面试八股文收集2

https://blog.csdn.net/weixin_45927841/article/details/123217462?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-123217462-blog-124825404.pc_relevant_antiscanv3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-123217462-blog-124825404.pc_relevant_antiscanv3&utm_relevant_index=2

作者:晗江雪
链接:https://www.nowcoder.com/discuss/836019
来源:牛客网

这里写目录标题

  • JAVA基础
    • JAVA反射
      • 什么是反射?
      • 为什么需要反射?
    • JAVA接口
      • 为什么要用接口
    • JAVA构造方法
    • JAVA集合
      • 哪些集合类是线程安全的?
      • list :LinkedList,ArrayList 和vector
      • set:HashSet和TreeSet
      • map:HashMap、TreeMap和HashTable
        • 线程安全
        • 空值
        • 继承和接口
        • 顺序
        • 构造函数
        • 数据结构
      • list、set和map的区别
      • ArrayList与LinkedList的区别
    • java面向对象
    • Java的基础数据类型有哪些?(5分)
    • int 和 Integer 有什么区别?(5分)
    • ArrayList和LinkedList有什么区别
    • JAVA中的集合类
      • 第一代线程安全集合类
      • 第二代线程非安全集合类
      • 第三代线程安全集合类
    • jdk1.8的新特性有哪些
        • 接口的默认方法
    • JAVA中抽象类和接口有什么区别
    • Java中==和equals有哪些区别
    • Java中重写和重载有哪些区别
    • String ,StringBuffer,StringBuilder区别及使用场景
  • Redis
    • Redis线程模型有哪些,单线程为什么快
    • JAVA中的数据结构
      • Java哈希表
        • hashCode() 和equals()方法的重要性体现在上面地方?
        • 请说一说,Java中的HashMap的工作原理是什么?
        • 介绍一下,什么是hashmap?
    • HashMap和LinkedHashMap的区别?
    • HashMap和HashTable有什么区别?
    • final关键字在Java中有什么作用?
    • static的作用
      • super的作用
    • String的底层存储是什么?
    • sleep()与wait()区别?(5分)
    • MySQL索引有哪几种类型?
    • MySQL之事务的四大特性?
    • 怎么避免并发?
    • MySQL中count(id)、count(1)、count(字段)的区别?
    • 你知道哪些数据库优化事项?
    • 抽象类和普通类有哪些区别?(5分)
    • java反射获取类的三种方式
    • HashSet 判断两个元素相等性的方法
  • Java多线程
    • 为什么要使用java线程池
  • Redis
    • Redis可以用来做什么
    • Redis和传统的关系型数据库有什么不同?
    • Redis有哪些数据类型
    • Redis为什么是单线程的却这么快
    • set和zset有什么区别呢
    • 1.7 说一下Redis中的watch命令
    • 1.8 说说Redis中List结构的相关操作
    • 1.9 你要如何设计Redis的过期时间?
  • MySQL部分
    • 存储引擎的区别
    • 说一说你对数据库优化的理解
    • 该如何优化Mysql的查询
    • 了解数据库的锁吗?
    • 怎么样插入数据才能高效?
    • 数据库在什么情况下会发生死锁?
    • 说说数据库死锁的解决办法
    • 介绍一下数据库分页
    • 介绍一下SQL中的聚合函数
    • 表跟表之间是怎么关联的?
    • 说一说你对外连接的了解
    • 说一说数据库的左连接和右连接
    • Where和HAVING有什么区别
    • 索引
      • 说一说你对Mysql索引的理解
      • mysql有哪些索引
      • MySQL怎么判断要不要加索引
      • 那些情况不适合创建索引
      • 索引的实现原理
      • 聚簇索引有哪些类别
      • 聚簇索引和非聚簇索引有什么区别
      • mysql的存储引擎有哪些
      • Mysql的隔离级别有哪些?
    • 单例模式
    • 手写一个单例模式
      • 手写一个线程安全的单例模式
  • 高并发
    • 高并发有哪些实践方案
    • 高性能的时间方案
    • 3.2.2 高可用的实践方案
    • 3.2.3 高扩展的实践方案
    • get请求与post请求有什么区别?
    • Linux简单命令
      • 查看空间,内存
      • 查询日志
      • 查端口号
      • mikdir——Make Directory
      • pwd — Print Working Directory
      • cd — Change Directory
      • .rmdir— Remove Directory
      • rm— Remove
      • cp— Copy
      • mv— Move
      • grep
      • find
      • tar
      • gzip

JAVA基础

JAVA反射

什么是反射?

反射是JAVA的特征之一,它允许运行中的JAVA程序对自身的检查
反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,被,被private封装的资源只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。
反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。

为什么需要反射?

如果向创建对象,我们可以直接new User();为何要通过反射去创建对象呢?

那我要先问你个问题了,你为什么要去餐馆吃饭呢?
例如:我们要吃个牛排大餐,如果我们自己创建,就什么都得管理。
好处是,每一步做什么我都很清晰,坏处是什么都得自己实现,那不是累死了。牛接生你管,吃什么你管,屠宰你管,运输你管,冷藏你管,烹饪你管,上桌你管。就拿做菜来说,你能有特级厨师做的好?
那怎么办呢?有句话说的好,专业的事情交给专业的人做,饲养交给农场主,屠宰交给刽子手,烹饪交给特级厨师。那我们干嘛呢?
我们翘起二郎腿直接拿过来吃就好了。
再者,饭店把东西做好,不能扔到地上,我们去捡着吃吧,那不是都成原始人了。那怎么办呢?很简单,把做好的东西放在一个容器中吧,如把牛排放在盘子里。

我们在后面的学习中,会学习框架,有一个框架Spring就是一个非常专业且功能强大的产品,它可以帮我们创建对象,管理对象。以后我无需手动new对象,直接从Spring提供的容器中的Beans获取即可。Beans底层其实就是一个Map,最终通过getBean(“user”)来获取。而这其中最核心的实现就是利用反射技术。

总结一句,类不是你创建的,是你同事或者直接是第三方公司,此时你要或得这个类的底层功能调用,就需要反射技术实现。有点抽象,别着急,我们做个案例,你就立马清晰。

package cn.tedu.reflection;

import java.lang.reflect.Constructor;

import org.junit.Test;

/**本类用来测试反射*/
public class TestReflect {
//7.通过单元测试方法,创建Student目标类的对象
    @Test
    public void getObject() throws Exception {
        //1.获取字节码对象
        Class<?> clazz = Student.class;
        //2.通过反射技术创建目标类的对象,注意抛出异常
        /*反射创建对象方案1:通过触发目标类的无参构造创建对象*/
        Object o = clazz.newInstance();
        System.out.println(o);//这一步已经获取到了对象Student{name='null', age=0}

        /*反射创建对象方案2:通过触发目标类的全参构造创建对象
        * 思路:
        * 1.先获取指定的构造函数对象,注意需要指定构造函数的参数,传入的是.class字节码对象
        * 2.通过刚刚获取到的构造函数对象创建Student目标类的对象,并且给对象的属性赋值
        * */
        //3.获取目标类中指定的全参构造
        Constructor<?> c = clazz.getConstructor(String.class, int.class);
        //System.out.println(c);
        //4.通过获取到的构造函数:创建对象+给对象的属性赋值
        Object o2 = c.newInstance("赵六", 6);
        System.out.println(o2);
    }
}

JAVA接口

为什么要用接口

接口被用来描述一种抽象。因为JAVA不像C++一样支持多继承,所以JAVA可以通过实现接口来弥补这个局限
接口也可以用来实现解耦。
接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?原因是抽象类内部可能包含非final的变量,接口的静态成员变量要用static final public 来修饰
\接口中的方法都是抽象的,是没有方法体的,可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。

可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)

和抽象类区别:

● 抽象类实例化是变量指向实现抽象方法的子类对象,接口变量必须实现所有接口方法的类对象
● 抽象类要被子类继承,接口被类实现
● 接口只能做方法申明,抽象类可以做方法实现
● 接口定义的变量只能是公共的静态的常量,抽象类中是普通变量
● 接口可以通过匿名内部类实例化

● 一个抽象类可以是public、private、protected、default,接口只有public;
● 一个抽象类中的方法可以是public、private、protected、default,接口中的方法只能是public和default
● abstract不能与final并列修饰同一个类;abstract 不能与private、static、final或native并列修饰同一个方法
● 抽象方法不能有方法体,抽象方法不能使用private修饰符,也不宜使用默认修饰符(default)接口 不可以实例化 。 通过接口实现类创建对象

JAVA构造方法

构造方法的声明:
修饰符 class_name(类名)  (参数列表){
 逻辑代码
}
  1. 构造⽅法的⽅法名和类名⼀致(包括⼤⼩写)
  2. 构造⽅法没有返回值类型(连void都没有)
  3. 构造⽅法可以重载
  4. 构造⽅法不可以⼿动调⽤,只能在创建对象的时,jvm⾃动调⽤
  5. 构造⽅法在创建对象时只能调⽤⼀次
  6. 构造⽅法的⽅法名和类名⼀致(包括⼤⼩写)
  7. 构造⽅法没有返回值类型(连void都没有)
  8. 构造⽅法可以重载
  9. 构造⽅法不可以⼿动调⽤,只能在创建对象的时,jvm⾃动调⽤
  10. 构造⽅法在创建对象时只能调⽤⼀次

当⼀个类中,没有定义构造⽅法 系统会⾃动提供⼀个公开的 ⽆参的构造⽅法 当类中已经定义了构 造⽅法,系统不再提供⽆参公开构造,如果需要使⽤⽆参的构造 那么必须⾃⼰定义出来 ⼀般开发如果 定义了有参的构造 都会再定义⼀个⽆参的构造

构造方法不能被 static、final、synchronized、abstract 和 native(类似于 abstract)修饰。构造方法用于初始化一个新对象,所以用 static 修饰没有意义。构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义。

构造函数的作用是创建一个类的实例。用来创建一个对象,同时可以给属性做初始化。当程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化。

JAVA集合

哪些集合类是线程安全的?

Vector、Hashtable、Stack 都是线程安全的,而像 HashMap 则是非线程安全的,不过在 jdk 1.5 之后随着 java.util.concurrent 并发包的出现,它们也有了自己对应的线程安全类,比如 HashMap 对应的线程安全类就是 ConcurrentHashMap。

list :LinkedList,ArrayList 和vector

LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
Vector 接口实现类 数组, 同步, 线程安全

set:HashSet和TreeSet

HashSet 使用哈希表存储元素,元素可以是null
LinkedHashSet 链表维护元素的插入次序
TreeSet 底层实现为红黑树,元素排好序,元素不可以是null

map:HashMap、TreeMap和HashTable

线程安全

HshaMap线程不安全
TreeMap线程不安全
HashTable线程安全

空值

HashMap一个null key,多个null value
TreeMap不能null key,多个null value
HashTable都不能有null

继承和接口

HashMap继承AbstractMap,实现接口Map
TreeMap继承AbstractMap,实现接口NavigableMap(SortMap的一种)
HashTable继承Dictionary,实现接口Map

顺序

HashMap中key是无序的
TreeMap是有序的
HashTable是无序的

构造函数

HashMap有调优初始容量和负载因子
TreeMap没有
HashTable有

数据结构

HashMap是链表+数组+红黑树
TreeMap是红黑树
HashTable是链表+数组

list、set和map的区别

list:元素按进入先后有序保存,可重复
set:不可重复,并做内部排序
map:代表具有映射关系的集合,其所有的key是一个Set集合,即key无序且不能重复。

Collection:单列集合的根接口

Map:双列集合的根接口,用于存储具有键(key)、值(value)映射关系的元素。

List:元素有序 可重复

● ArrayList:类似一个长度可变的数组 。适合查询,不适合增删
● LinkedList:底层是双向循环链表。适合增删,不适合查询。

Set:元素无序,不可重复

● HashSet:根据对象的哈希值确定元素在集合中的位置
● TreeSet: 以二叉树的方式存储元素,实现了对集合中的元素排序

LinkedHashSet继承于HashSet、又基于 LinkedHashMap 来实现

TreeSet使用二叉树的原理对新 add()的对象按照指定的顺序排序(升序、降序),每增加一个对象都会进行排序,将对象插入的二叉树指定的位置。

HashSet存储元素的顺序并不是按照存入时的顺序(和 List 显然不同) 而是按照哈希值来存的所以取数据也是按照哈希值取得

ArrayList与LinkedList的区别

● arrayList使用的是数组数据结构,可以以O(1)时间复杂度对元素进行随机访问;LinkedList使用的是(双)链表结构查找某个元素的时间复杂度是O(n)
● arrayList更适合于随机查找操作,linkedList更适合增删改查,时间复杂度根据数据浮动
● 两者都实现了List接口,但LinkedList额外实现了Deque接口,因此Linked还可以当作队列使用
● LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素

 //遍历ArrayList
    public static void main(String args[]){
        List<String> list = new ArrayList<String>();
        list.add("luojiahui");
        list.add("luojiafeng");

        //方法1
        Iterator it1 = list.iterator();
        while(it1.hasNext()){
            System.out.println(it1.next());
        }

        //方法2
        for(Iterator it2 = list.iterator();it2.hasNext();){
             System.out.println(it2.next());
        }

        //方法3
        for(String tmp:list){
            System.out.println(tmp);
        }

        //方法4
        for(int i = 0;i < list.size(); i ++){
            System.out.println(list.get(i));
        }

    }

java面向对象

即封装继承多态
概论:面向对象是把一组数据结构和处理他们的方法组成对象;
把具有相同行为的对象归纳成类;通过封装隐藏类的内部细节;通过继承使类得到泛化;
通过多态实现基于对象类型的动态分派

吃饭:
面向过程:买菜,洗菜,做饭,洗手吃饭,洗碗
面向对象:点外卖,吃饭,扔外卖盒

封装:内部细节对外部调用透明
体现:1.JavaBean的属性私有,提供get set 对外访问,因为属性的赋值或者获取

Java的基础数据类型有哪些?(5分)

有布尔型 true false ,整数型long int byte short,字符类型char,浮点型float double

int 和 Integer 有什么区别?(5分)

Int 是基本数据类型,Integer是引用数据类型,Interger更多用于面向对象过程,即更多用于创建类过程中。

ArrayList和LinkedList有什么区别

ArrayList和LinkedList都实现了List接口,他们有以下的不通电
ArrayList是基于索引的数据接口,底层是数组,它可以以O(1)时间复杂度对元素进行随机访问。
对应的是LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,

总结:
ArrayList基于数组,LinkedList基于链表

JAVA中的集合类

第一代线程安全集合类

Vector,Hashtable
是怎么保证线程安排的;使用synchronized修饰方法
缺点:效率低下

第二代线程非安全集合类

ArrayList ,HashMap
线程不安全,但是性能好,用来代替vector和Hashtable
使用ArrayList ,HashMap,需要线程安全怎么办呢?
使用Collections.synchronizedList(list);Collections.synchronizedMap(m);
底层使用synchronized代码块锁,虽然也是锁住了所有代码,

第三代线程安全集合类

在大量并发情况下如何提高集合的效率和安全呢

jdk1.8的新特性有哪些

接口的默认方法

java8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,
示例如下:
代码如下:
interface Formula{
double calculate(int a)
default double sqrt(int a) {
return Math.sqrt(a);
}
}

JAVA中抽象类和接口有什么区别

不同
抽象类:
1.抽象类中可以定义构造器
2.可以有抽象方法和具体方法
3.接口中的成员全都是public的
4.抽象类中可以定义成员变量
5.有抽象方法的类必须声明为抽象类,而抽象类未必要有抽象方法
6.抽象类中可以包含静态方法
7.一个类只能继承一个抽象类

接口:
1.接口中不能定义构造器
2.方法全都是抽象方法
3.抽象类中的成员可以是private,默认,protected,public
4.接口中定义的成员变量实际上是常量
5.接口中不能有静态方法
6.一个类可以实现多个接口

Java中==和equals有哪些区别

equals和==最大的区别是一个是方法一个是运算符

==:如果比较的对象时基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等
equals(): 用来比较两个方法的内容是否相等。
注意:equals方法不能用于基本数据类型的变量,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向二代对象的地址。

● == : 对比的是栈中的值,基本数据类型是变量值,引用数据类型是堆中内存对象的地址;
直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的
● equals:object中默认也是采用==比较,通常会重写

== 是java提供的等于比较运算符,用来比较两个变量指向的内存地址是否相同.而equals()是Object提供的一个方法.Object中equals()方法的默认实现就是返回两个对象==的比较结果.但是equals()可以被重写,所以我们在具体使用的时候需要关注equals()方法有没有被重写.

Java中重写和重载有哪些区别

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性,重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同,参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法生命更多的

String ,StringBuffer,StringBuilder区别及使用场景

Java平台提供了两种类型的字符串:String和StringBuilder,它们都可以存储和操作字符串,区别如下。

1.String是只读字符串,也就意味着String引用的字符串内容是不能被改变的,初学者可能会有这样的误解:

String str ="abc";
str = "bad"

如上,字符串str命名是可以改变的吖!其实不然,str仅仅是一个是一个引用对象,它指向一个字符串对象“abc”,
第二行代码的含义是让str重新指向一个新的字符串"bcd"对象,而“abc”对象并没有任何改变,只不过该对象已经成为了一个不可及对象罢了

2.StringBuffer/StringBuffer表示的字符串对象可以直接修改
3.StringBuffer是java5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方法都没有被synchronized修饰,因此它的效率理论上也比StringBuffer要高。

Redis

Redis线程模型有哪些,单线程为什么快

JAVA中的数据结构

Java哈希表

hashCode() 和equals()方法的重要性体现在上面地方?

Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对HashMap的精确性和正确性是至关重要的。

请说一说,Java中的HashMap的工作原理是什么?

HashMap是以键值对的形式存储元素的,需要一个哈希函数,使用hashcode和eaquels方法,从集合中添加和检索元素,调用put方法时,会计算key 的哈希值,然后把键值对存在集合中合适的索引上,如果键key已经存在,value会被更新为新值。另外HashMap的初始容量是16,在jdk1.7的时候底层是基于数组和链表实现的,插入方式是头插法。jdk1.8的时候底层是基于数组和链表/红黑树实现的,插入方式为尾插法。

介绍一下,什么是hashmap?

HashMap 是一个散列表,它存储的内容是键值对(key-value)。
HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
HashMap 的实现不是同步的,所以它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。
HashMap 的实例有两个参数影响其性能:“初始容量” 和 “负载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。负载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
HashMap在扩容的时候是2的n次幂。

HashMap和LinkedHashMap的区别?

HashMap和HashTable有什么区别?

final关键字在Java中有什么作用?

可用来修饰类,方法,变量

1.final修饰变量,则等同于常量 2.final修饰方法中的参数,称为最终参数。

3.final修饰类,则类不能被继承 (太监类)

4.final修饰方法,则方法不能被重写。5.final 不能修饰抽象类

6.final修饰的方法可以被重载 但不能被重写 (不能继承)

  1. 当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类
  2. 使用final方法的原因有两个:第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。
    只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。 注:类的private方法会隐式地被指定为final方法
  3. 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变

即使没有final修饰的情况下,在方法内部改变了变量i的值也不会影响方法外的i;java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响

static的作用

static修饰的变量没有发生变化是因为static作用于成员变量只是用来表示保存一份副本,其不会发生变化。怎么理解这个副本呢?其实static修饰的在类加载的时候就加载完成了(初始化),而且只会加载一次也就是说初始化一次,所以不会发生变化!

static是不允许用来修饰局部变量 静态变量只能在类主体中定义,不能在方法中定义

● 静态变量:
静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中JVM只为静态变量分配一次内存空间。
● 实例变量:
每次创建对象都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

super的作用

● 调用父类被子类重写的方法;
● 调用父类被子类重定义的字段(被隐藏的成员变量);
● 调用父类的构造方法;

如果子类没有重写父类的方法,调用父类的方法用不用super关键字结果都一样。 如果子类重写父类的方法,调用父类的方法必须用super关键字

String的底层存储是什么?

sleep()与wait()区别?(5分)

MySQL索引有哪几种类型?

MySQL之事务的四大特性?

原子性,一致性,隔离性,持久性

怎么避免并发?

MySQL中count(id)、count(1)、count(字段)的区别?

你知道哪些数据库优化事项?

抽象类和普通类有哪些区别?(5分)

抽象类只能用public 和protected来修饰,
抽象类不可以用来创建对象

java反射获取类的三种方式

1.调用对象的.getClass()方法
2.调用某个类的.class属性
3.使用Class.forName+类的全路径

HashSet 判断两个元素相等性的方法

HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法,如果equls结果为true,HashSet就是为一个元素,如果equals为false,就不是一个元素

Java多线程

为什么要使用java线程池

1.降低资源消耗。通过重复利用已创建的线程降低线程创建,销毁线程造成的消耗。
2.提高响应速度。当任务到达时,任务可以不需要等到线程创建就立即执行。
3.提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
4.提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

Redis

Redis可以用来做什么

1.Redis最长用来做缓存,是实现分布式缓存的首先中间件
2.Redis可以作为数据库,实现诸如点赞,关注,排行等对性能要求极高的互联网需求
3.Redis可以作为计算工具,能用很小的代价,统计诸如PV/UV,用户在线天数等数据
4.Redis还有很多其他的使用场景,例如:可以实现分布式锁,可以作为消息队列使用。

Redis和传统的关系型数据库有什么不同?

Redis是一种基于键值对的NoSQL数据库,而键值对的值是由多种数据结构和算法组成的。Redis的数据都存储与内存中,因此它的速度惊人,读写性能可达10万/秒,远超关系型数据库

关系型数据库是基于二维数据表来存储数据的,它的数据格式更为严谨,并支持关系查询。关系型数据库的数据存储于磁盘上,可以存放海量的数据,但性能远不如Redis

区别:
NoSQL存放在内存中,关系型数据库存放在磁盘中

Redis有哪些数据类型

1.Redis支持5中核心的数据类型,分别是字符串,哈希,列表,集合,有序集合
2.Redis还提供了Bitmap,HyperLogLog,Geo类型,但是这些都是基于上述的核心数据类型实现的
3.Redis在5.0新增加了Streams数据类型,它是一个功能强大的、支持多播的、可持久化的消息队列。

Redis为什么是单线程的却这么快

1.单线程避免了线程切换和竞争所产生的消耗
2.Redis大部分操作在内存上完成
3.Redis采用了IO多路复用机制,使其在网络IO操作中能并发处理大量的客户端请求,实现高吞吐率。

set和zset有什么区别呢

set:即集合

集合中的元素是无序、不可重复的,一个集合最多能存储232-1个元素;

集合除了支持对元素的增删改查之外,还支持对多个集合取交集、并集、差集。

zset:即有序集合

有序集合保留了集合元素不能重复的特点;

有序集合会给每个元素设置一个分数,并以此作为排序的依据;

有序集合不能包含相同的元素,但是不同元素的分数可以相同。

1.7 说一下Redis中的watch命令

参考答案

很多时候,要确保事务中的数据没有被其他客户端修改才执行该事务。Redis提供了watch命令来解决这类问题,这是一种乐观锁的机制。客户端通过watch命令,要求服务器对一个或多个key进行监视,如果在客户端执行事务之前,这些key发生了变化,则服务器将拒绝执行客户端提交的事务,并向它返回一个空值。

1.8 说说Redis中List结构的相关操作

参考答案

列表是线性有序的数据结构,它内部的元素是可以重复的,并且一个列表最多能存储2^32-1个元素。列表包含如下的常用命令:

lpush/rpush:从列表的左侧/右侧添加数据;

lrange:指定索引范围,并返回这个范围内的数据;

lindex:返回指定索引处的数据;

lpop/rpop:从列表的左侧/右侧弹出一个数据;

blpop/brpop:从列表的左侧/右侧弹出一个数据,若列表为空则进入阻塞状态。

1.9 你要如何设计Redis的过期时间?

参考答案

热点数据不设置过期时间,使其达到“物理”上的永不过期,可以避免缓存击穿问题;

在设置过期时间时,可以附加一个随机数,避免大量的key同时过期,导致缓存雪崩。

MySQL部分

存储引擎的区别

InnoDB拥有事务和外键,而MyISAM则没有,InnoDB使用聚集索引,MyISAM是非聚集索引标,InnoDB所用的是行锁 表锁,MyISAM用的是表锁,InnoDB操作中Insert与Update效率更高,MyISAMSelect效率更高
DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令 参考链接

1.InnoDB 支持事务,MyISAM 不支持事务。这是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

\2. InnoDB 支持事务,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM 会失败;

\3. InnoDB 是聚集索引,MyISAM 是非聚集索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

\4. InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;

\5. InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

关系数据模型的三个组成部分 完整性规则、 数据结构、 数据操作。

● 数据结构:描述数据库的组成对象以及对象之间的联系。
● 数据操作:指对数据库中各种对象(型)的实例(值)允许执行的操作的集合,包括操作及有关的操作规则。
● 数据的完整性约束规则:一组完整性规则。

说一说你对数据库优化的理解

数据库的优化是多方面的,原则就是减少系统的瓶颈,减少资源的占用,增加系统的反应速度。
例如,通过优化文件系统,提高磁盘I\O的读写速度;通过优化操作系统调度策略,提高MySQL在高负荷情况下的负载能力;优化表结构、索引、查询语句等使查询响应更快。

针对查询,我们可以通过使用索引、使用连接代替子查询的方式来提高查询速度。

针对慢查询,我们可以通过分析慢查询日志,来发现引起慢查询的原因,从而有针对性的进行优化。

针对插入,我们可以通过禁用索引、禁用检查等方式来提高插入速度,在插入之后再启用索引和检查。

针对数据库结构,我们可以通过将字段很多的表拆分成多张表、增加中间表、增加冗余字段等方式进行优化。

该如何优化Mysql的查询

使用索引:

如果查询时没有使用索引,查询语句将扫描表中的所有记录。在数据量大的情况下,这样查询的速度会很慢。如果使用索引进行查询,查询语句可以根据索引快速定位到待查询记录,从而减少查询的记录数,达到提高查询速度的目的。

索引可以提高查询的速度,但并不是使用带有索引的字段查询时索引都会起作用。有几种特殊情况,在这些情况下有可能使用带有索引的字段查询时索引并没有起作用。

使用LIKE关键字的查询语句

在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,索引不会起作用。只有“%”不在第一个位置,索引才会起作用。

使用多列索引的查询语句

MySQL可以为多个字段创建索引。一个索引可以包括16个字段。对于多列索引,只有查询条件中使用了这些字段中的第1个字段时索引才会被使用。

使用OR关键字的查询语句

查询语句的查询条件中只有OR关键字,且OR前后的两个条件中的列都是索引时,查询中才使用索引。否则,查询将不使用索引。

优化子查询:

使用子查询可以进行SELECT语句的嵌套查询,即一个SELECT查询的结果作为另一个SELECT语句的条件。子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作。

子查询虽然可以使查询语句很灵活,但执行效率不高。执行子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比较大,这种影响就会随之增大。

在MySQL中,可以使用连接(JOIN)查询来替代子查询。连接查询不需要建立临时表,其速度比子查询要快,如果查询中使用索引,性能会更好。

了解数据库的锁吗?

锁是数据库系统区别于文件系统的一个关键特性,锁机制用于管理对共享资源的并发访问。
下面以Mysql数据库的InnoDB引擎为例:来说明锁的一些特点。

锁:
InnoDB存储引擎实现了如下两种标准的行级锁:
共享锁:允许事务读取一行数据
排他锁:允许事务删除或更新一行数据
如果一个事务T1已经获得了行r的共享锁,那么另外的事务T2可以立即获得行r的共享锁,因为读取并没有改变行r的数据,称这种情况为锁兼容。但若有其他的事务T3想获得行r的排他锁,则其必须等待事务T1、T2释放行r上的共享锁,这种情况称为锁不兼容。下图显示了共享锁和排他锁的兼容性,可以发现X锁与任何的锁都不兼容,而S锁仅和S锁兼容。需要特别注意的是,S和X锁都是行锁,兼容是指对同一记录(row)锁的兼容性情况。
锁的粒度:

InnoDB存储引擎支持多粒度锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,称之为意向锁。意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁。

InnoDB存储引擎支持意向锁设计比较简练,其意向锁即为表级别的锁。设计目的主要是为了在一个事务中揭示下一行将被请求的锁类型。其支持两种意向锁:

意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁。

意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁。

由于InnoDB存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫以外的任何请求。故表级意向锁与行级锁的兼容性如下图所示。

锁的算法:

InnoDB存储引擎有3种行锁的算法,其分别是:

Record Lock:单个行记录上的锁。

Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。

Next-Key Lock∶Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身。

Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。采用Next-Key Lock的锁定技术称为Next-Key Locking,其设计的目的是为了解决Phantom Problem(幻读)。而利用这种锁定技术,锁定的不是单个值,而是一个范围,是谓词锁(predict lock)的一种改进。

关于死锁:

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。若无外力作用,事务都将无法推进下去。

解决死锁问题最简单的一种方法是超时,即当两个事务互相等待时,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚,另一个等待的事务就能继续进行。

除了超时机制,当前数据库还都普遍采用wait-for graph(等待图)的方式来进行死锁检测。较之超时的解决方案,这是一种更为主动的死锁检测方式。InnoDB存储引擎也采用的这种方式。wait-for graph要求数据库保存以下两种信息:

锁的信息链表;

事务等待链表;

通过上述链表可以构造出一张图,而在这个图中若存在回路,就代表存在死锁,因此资源间相互发生等待。这是一种较为主动的死锁检测机制,在每个事务请求锁并发生等待时都会判断是否存在回路,若存在则有死锁,通常来说InnoDB存储引擎选择回滚undo量最小的事务。

锁的升级:

锁升级(Lock Escalation)是指将当前锁的粒度降低。举例来说,数据库可以把一个表的1000个行锁升级为一个页锁,或者将页锁升级为表锁。

InnoDB存储引擎不存在锁升级的问题。因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的。

怎么样插入数据才能高效?

影响插入速度的主要是索引、唯一性校验、一次插入记录条数等。针对这些情况,可以分别进行优化。

对于MyISAM引擎的表,常见的优化方法如下:

禁用索引

对于非空表,插入记录时,MySQL会根据表的索引对插入的记录建立索引。如果插入大量数据,建立索引会降低插入记录的速度。为了解决这种情况,可以在插入记录之前禁用索引,数据插入完毕后再开启索引。对于空表批量导入数据,则不需要进行此操作,因为MyISAM引擎的表是在导入数据之后才建立索引的。

禁用唯一性检查

插入数据时,MySQL会对插入的记录进行唯一性校验。这种唯一性校验也会降低插入记录的速度。为了降低这种情况对查询速度的影响,可以在插入记录之前禁用唯一性检查,等到记录插入完毕后再开启。

使用批量插入

插入多条记录时,可以使用一条INSERT语句插入一条记录,也可以使用一条INSERT语句插入多条记录。使用一条INSERT语句插入多条记录的情形如下,而这种方式的插入速度更快。

INSERT INTO fruits VALUES (‘x1’, ‘101’, ‘mongo2’, ‘5.7’), (‘x2’, ‘101’, ‘mongo3’, ‘5.7’), (‘x3’, ‘101’, ‘mongo4’, ‘5.7’);
使用LOAD DATA INFILE批量导入

当需要批量导入数据时,如果能用LOAD DATA INFILE语句,就尽量使用。因为LOAD DATA INFILE语句导入数据的速度比INSERT语句快。

对于InnoDB引擎的表,常见的优化方法如下:

禁用唯一性检查

插入数据之前执行set unique_checks=0来禁止对唯一索引的检查,数据导入完成之后再运行set unique_checks=1。这个和MyISAM引擎的使用方法一样。

禁用外键检查

插入数据之前执行禁止对外键的检查,数据插入完成之后再恢复对外键的检查。

禁用自动提交

插入数据之前禁止事务的自动提交,数据导入完成之后,执行恢复自动提交操作。

数据库在什么情况下会发生死锁?

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。若无外力作用,事务都将无法推进下去。下图演示了死锁的一种经典的情况,即A等待B、B等待A,这种死锁问题被称为AB-BA死锁。

说说数据库死锁的解决办法

解决死锁问题最简单的一种方法是超时,即当两个事务互相等待时,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚,另一个等待的事务就能继续进行。

除了超时机制,当前数据库还都普遍采用wait-for graph(等待图)的方式来进行死锁检测。较之超时的解决方案,这是一种更为主动的死锁检测方式。InnoDB存储引擎也采用的这种方式。wait-for graph要求数据库保存以下两种信息:

锁的信息链表;

事务等待链表;

通过上述链表可以构造出一张图,而在这个图中若存在回路,就代表存在死锁,因此资源间相互发生等待。这是一种较为主动的死锁检测机制,在每个事务请求锁并发生等待时都会判断是否存在回路,若存在则有死锁,通常来说InnoDB存储引擎选择回滚undo量最小的事务。

介绍一下数据库分页

mysql的分页语法:
在mysql中,select语句默认返回所有匹配的行,它们可能是指定表中的每个行,为了返回第一行或者前几行,可使用LIMIT子句,以实现分页查询.LIMIT子句的语法如下:、

-- 在所有的查询结果中,返回前5行记录。 
SELECT prod_name FROM products LIMIT 5; 
-- 在所有的查询结果中,从第5行开始,返回5行记录。 
SELECT prod_name FROM products LIMIT 5,5;

介绍一下SQL中的聚合函数

常用的聚合函数有COUNT()、AVG()、SUM()、MAX()、MIN(),下面以MySQL为例,说明这些函数的作用。
COUNT()函数:

COUNT()函数统计数据表中包含的记录行的总数,或者根据查询结果返回列中包含的数据行数,它有两种用法:

COUNT(*)计算表中总的行数,不管某列是否有数值或者为空值。

COUNT(字段名)计算指定列下总的行数,计算时将忽略空值的行。

COUNT()函数可以与GROUP BY一起使用来计算每个分组的总和。

AVG()函数():

AVG()函数通过计算返回的行数和每一行数据的和,求得指定列数据的平均值。

AVG()函数可以与GROUP BY一起使用,来计算每个分组的平均值。

SUM()函数:

SUM()是一个求总和的函数,返回指定列值的总和。

SUM()可以与GROUP BY一起使用,来计算每个分组的总和。

MAX()函数:

MAX()返回指定列中的最大值。

MAX()也可以和GROUP BY关键字一起使用,求每个分组中的最大值。

MAX()函数不仅适用于查找数值类型,也可应用于字符类型。

MIN()函数:

MIN()返回查询列中的最小值。

MIN()也可以和GROUP BY关键字一起使用,求出每个分组中的最小值。

MIN()函数与MAX()函数类似,不仅适用于查找数值类型,也可应用于字符类型。

表跟表之间是怎么关联的?

表与表之间常用的关联方式有两种:内连接、外连接,下面以MySQL为例来说明这两种连接方式。

内连接:
内连接通过INNER JOIN来实现,它将返回两张表中满足连接条件的数据,不满足条件的数据不会查询出来。

外连接:
外连接通过OUTER JOIN来实现,它会返回两张表中满足连接条件的数据,同时返回不满足连接条件的数据。外连接有两种形式:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)。

左外连接:可以简称为左连接(LEFT JOIN),它会返回左表中的所有记录和右表中满足连接条件的记录。

右外连接:可以简称为右连接(RIGHT JOIN),它会返回右表中的所有记录和左表中满足连接条件的记录。

除此之外,还有一种常见的连接方式:等值连接。这种连接是通过WHERE子句中的条件,将两张表连接在一起,它的实际效果等同于内连接。出于语义清晰的考虑,一般更建议使用内连接,而不是等值连接。

以上是从语法上来说明表与表之间关联的实现方式,而从表的关系上来说,比较常见的关联关系有:一对多关联、多对多关联、自关联。

一对多关联:这种关联形式最为常见,一般是两张表具有主从关系,并且以主表的主键关联从表的外键来实现这种关联关系。另外,以从表的角度来看,它们是具有多对一关系的,所以不再赘述多对一关联了。

多对多关联:这种关联关系比较复杂,如果两张表具有多对多的关系,那么它们之间需要有一张中间表来作为衔接,以实现这种关联关系。这个中间表要设计两列,分别存储那两张表的主键。因此,这两张表中的任何一方,都与中间表形成了一对多关系,从而在这个中间表上建立起了多对多关系。

自关联:自关联就是一张表自己与自己相关联,为了避免表名的冲突,需要在关联时通过别名将它们当做两张表来看待。一般在表中数据具有层级(树状)时,可以采用自关联一次性查询出多层级的数据。

说一说你对外连接的了解

外连接通过OUTER JOIN来实现,它会返回两张表中满足连接条件的数据,同时返回不满足连接条件的数据。常见的外连接有两种形式:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)。

左外连接:可以简称为左连接(LEFT JOIN),它会返回左表中的所有记录和右表中满足连接条件的记录。

右外连接:可以简称为右连接(RIGHT JOIN),它会返回右表中的所有记录和左表中满足连接条件的记录。

实际上,外连接还有一种形式:完全外连接(FULL OUTER JOIN),但MySQL不支持这种形式。

说一说数据库的左连接和右连接

外连接通过OUTER JOIN来实现,它会返回两张表中满足连接条件的数据,同时返回不满足连接条件的数据。常见的外连接有两种形式:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)。

左外连接:可以简称为左连接(LEFT JOIN),它会返回左表中的所有记录和右表中满足连接条件的记录。

右外连接:可以简称为右连接(RIGHT JOIN),它会返回右表中的所有记录和左表中满足连接条件的记录。

Where和HAVING有什么区别

WHERE是一个约束声明,使用WHERE约束来自数据库的数据,WHERE是在结果返回之前起作用的,WHERE中不能使用聚合函数。

HAVING是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作,在HAVING中可以使用聚合函数。另一方面,HAVING子句中不能使用除了分组字段和聚合函数之外的其他字段。

从性能的角度来说,HAVING子句中如果使用了分组字段作为过滤条件,应该替换成WHERE子句。因为WHERE可以在执行分组操作和计算聚合函数之前过滤掉不需要的数据,性能会更好。

索引

说一说你对Mysql索引的理解

索引是一个单
独的,存储在磁盘上的数据库结构,包含着对数据库表里所有记录的引用指针。使用索引可以加快找出在某个或多个列中有一特定值的行,所有MySQL列类型都可以被索引,对相关列使用索引是提高查询和操作速度的最佳途径

索引是在存储引擎中实现的,因此,每种存储引擎的索引都不一定完全相同,并且每种存储引擎也不一定支持所有的索引类型。MySQL中索引的存储类型有两种,即Btree和HASH,具体和表的存储引擎相关

索引的有点主要有以下几条:
1.通过创建唯一索引,可以保证数据库表中每一行数据的唯一性
2.可以大大加快数据的查询速度。
3.有助于实现数据的参考完整性,可以加速表和表之间的链接
4.使用分组和排序子句进行数据查询时,可以显著减少查询中分组和排序的时间

增加索引也有许多不利的方面,主要表现在如下几个方面:
1.创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加
2.索引需要占据磁盘空间,除了数据表占数据空间之外,每一个索引还需要占一定的物理空间,如果有大量的索引,索引文件可能比数据文件更大
3.当对表中的数据进行增删改的时候,索引也要动态地维护,这样降低了数据的维护速度

mysql有哪些索引

可以分为以下几类:
1.普通索引和唯一索引
普通索引是MySQL中的基本索引类型,允许在定义索引的列中插入重复值和空值。
唯一索引要求索引列的值必须唯一,但允许有空值,如果是组合索引,则组合的值必须唯一。
主键索引是一种特殊的唯一索引,不允许有空值。

2.单列索引和组合索引
单列索引即一个索引只包含单个列,一个表可以有多个单列索引。
组合索引是指在表的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用。使用组合索引时遵循最左前缀集合

3.全文索引
4.空间索引

MySQL怎么判断要不要加索引

建议按照如下的原则来创建索引:

当唯一性是某种数据本身的特征时,指定唯一索引。使用唯一索引需能确保定义的列的数据完整性,以提高查询速度。

在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引,如果待排序的列有多个,可以在这些列上建立组合索引。

那些情况不适合创建索引

1.频繁更新的字段
2.where条件中用不到的字段
3.数据比较少的表
4.数据重复且分布比较均匀的字段,比如性别,真价值
5.参与列计算的列不适合建索引

索引的实现原理

在MySQL中,索引是在存储引擎层实现的,不同存储引擎对索引的实现方式是不同的,下面我们探讨一下MyISAM和InnoDB两个存储引擎的索引实现方式。

MyISAM索引实现:

MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址,MyISAM索引的原理图如下。这里假设表一共有三列,假设我们以Col1为主键,则上图是一个MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。
如果我们在Col2上建立一个辅助索引,则此索引的结构如下图所示。同样也是一颗B+Tree,data域保存数据记录的地址。因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。

InnoDB索引实现:

虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。

第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

下图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。下图为定义在Col3上的一个辅助索引。这里以英文字符的ASCII码作为比较准则。聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

了解不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

聚簇索引有哪些类别

聚簇索引和非聚簇索引有什么区别

在InnoDB存储引擎中,可以将B+树索引分为聚簇索引和辅助索引(非聚簇索引)。无论是何种索引,每个页的大小都为16KB,且不能更改。

聚簇索引是根据主键创建的一棵B+树,聚簇索引的叶子节点存放了表中的所有记录。辅助索引是根据索引键创建的一棵B+树,与聚簇索引不同的是,其叶子节点仅存放索引键值,以及该索引键值指向的主键。也就是说,如果通过辅助索引来查找数据,那么当找到辅助索引的叶子节点后,很有可能还需要根据主键值查找聚簇索引来得到数据,这种查找方式又被称为书签查找。因为辅助索引不包含行记录的所有数据,这就意味着每页可以存放更多的键值,因此其高度一般都要小于聚簇索引。

mysql的存储引擎有哪些

MySQL的存储引擎有MyISAM和InnoDB,MEMORY/HEAP
MyISAM和InnoDB存储引擎只支持BTREE索引
MEMORY/HEAP存储引擎可以支持HASH和BTREE索引。

Mysql的隔离级别有哪些?

Mysql定义了四种隔离级别,包括一些具体规则,用于限定事物内外哪些改变是可见的,哪些改变时不可见的。
低级别的隔离一般支持更高的并发处理,并且拥有更低的系统开销

READ UNCOMMITTED 读取未提交内容

在这个隔离级别,所有事物都可以“看到”未提交事物的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在干什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不比其他性能好多少,而别的级别还有其他更多的优点,读取未提交数据,也被称为“脏读”

READ COMMITTED 读取提交内容
大多数数据库的默认隔离级别(但是不是MySQL的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见”已经提交事务所做的改变,一个事务从开始到提交钱,所做的任何数据改变都是不可见的,除非已经提交,这种隔离级别也支持所谓的“不可重复读”,这意味着用户运行同一个语句两次,看到的结果是不同的。

repeatble read 可重复读
MySQL 数据库默认的隔离界别。该级别解决了read uncommitted隔离级别导致的问题。它保证同一事务的多个实例在并发读取事务时,会“看到同样的”数据行。

serializable 可串行化
强制给事务排序,使之不可能冲突

1.脏读
脏读是指一个事务读取了未提交事务执行过程中的数据。
当一个事务的操作正在多次修改数据,而在事务还未提交的时候,另外一个并发事务
2.不可重复读
3.虚读(幻读)

单例模式

优点

● 单例类只有一个实例对象,节省了系统资源(省去了对象的频繁创建 与销毁);
● 该单例对象必须由单例类自行创建;
● 单例类对外提供一个访问该单例的全局访问点。

缺点

● 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
● 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
● 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

使用场景

● 需要频繁的进行创建和销毁的对象;
● 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
● 工具类对象;
● 频繁访问数据库或文件的对象。

手写一个单例模式

饿汉式单例模式

public class Singleton {     
private static Singleton instance = new Singleton(); 
    // 私有构造方法,保证外界无法直接实例化。
         private Singleton() {}     
         // 通过公有的静态方法获取对象实例     
         public static Singleton getInstace() {         
         	return instance;     
         } 
 }
public class Singleton {
     private static Singleton instance = null; 
         // 私有构造方法,保证外界无法直接实例化。    
          private Singleton() {}     
          // 通过公有的静态方法获取对象实例    
           public static Singleton getInstace() {        
            if (instance == null) {             
            instance = new Singleton();         
            }        
             return instance;     
             }
    }

手写一个线程安全的单例模式

public class Singleton {     
private static Singleton instance = null; 
    // 私有构造方法,保证外界无法直接实例化。
         private Singleton() {
         }     
         // 通过公有的静态方法获取对象实例     synchronized public static Singleton getInstace() {         if (instance == null) {             instance = new Singleton();        
          }
                   return instance;
                        } 
             }

高并发

高并发有哪些实践方案

要实现高并发,一般针对高性能,高可用,高扩展3个方面,总结一下可落地的实践方案。

高性能的时间方案

1.集群部署,通过负载均衡减轻单机压力
2.多级缓存,包括静态数据使用CDN,本地缓存,分布式缓存等,以及处理对缓存场景中的热点key,缓存穿透,缓存并发,数据一致性等问题的处理。
3.分库分表和索引优化,以及借助搜索引擎解决复杂查询问题。
4.考虑NoSQL数据库的使用,比如HBase,TiDB等,但是团队必须熟悉这些组件,且有较强的运维能力
5.异步化,将次要流程通过多线程、MQ、甚至延时任务进行异步处理。
限流,需要先考虑业务是否允许限流(比如秒杀场景是允许的),包括前端限流、Nginx接入层的限流、服务端的限流。

对流量进行削峰填谷,通过MQ承接流量。

并发处理,通过多线程将串行逻辑并行化。

预计算,比如抢红包场景,可以提前计算好红包金额缓存起来,发红包时直接使用即可。

缓存预热,通过异步任务提前预热数据到本地缓存或者分布式缓存中。

减少IO次数,比如数据库和缓存的批量读写、RPC的批量接口支持、或者通过冗余数据的方式干掉RPC调用。

减少IO时的数据包大小,包括采用轻量级的通信协议、合适的数据结构、去掉接口中的多余字段、减少缓存key的大小、压缩缓存value等。

程序逻辑优化,比如将大概率阻断执行流程的判断逻辑前置、For循环的计算逻辑优化,或者采用更高效的算法。

各种池化技术的使用和池大小的设置,包括HTTP请求池、线程池(考虑CPU密集型还是IO密集型设置核心参数)、数据库和Redis连接池等。

JVM优化,包括新生代和老年代的大小、GC算法的选择等,尽可能减少GC频率和耗时。

锁选择,读多写少的场景用乐观锁,或者考虑通过分段锁的方式减少锁冲突。

上述方案无外乎从计算和 IO 两个维度考虑所有可能的优化点,需要有配套的监控系统实时了解当前的性能表现,并支撑你进行性能瓶颈分析,然后再遵循二八原则,抓主要矛盾进行优化。

3.2.2 高可用的实践方案

对等节点的故障转移,Nginx和服务治理框架均支持一个节点失败后访问另一个节点。

非对等节点的故障转移,通过心跳检测并实施主备切换(比如redis的哨兵模式或者集群模式、MySQL的主从切换等)。

接口层面的超时设置、重试策略和幂等设计。

降级处理:保证核心服务,牺牲非核心服务,必要时进行熔断;或者核心链路出问题时,有备选链路。

限流处理:对超过系统处理能力的请求直接拒绝或者返回错误码。

MQ场景的消息可靠性保证,包括producer端的重试机制、broker侧的持久化、consumer端的ack机制等。

灰度发布,能支持按机器维度进行小流量部署,观察系统日志和业务指标,等运行平稳后再推全量。

监控报警:全方位的监控体系,包括最基础的CPU、内存、磁盘、网络的监控,以及Web服务器、JVM、数据库、各类中间件的监控和业务指标的监控。

灾备演练:类似当前的“混沌工程”,对系统进行一些破坏性手段,观察局部故障是否会引起可用性问题。

高可用的方案主要从冗余、取舍、系统运维3个方向考虑,同时需要有配套的值班机制和故障处理流程,当出现线上问题时,可及时跟进处理。

3.2.3 高扩展的实践方案

合理的分层架构:比如上面谈到的互联网最常见的分层架构,另外还能进一步按照数据访问层、业务逻辑层对微服务做更细粒度的分层(但是需要评估性能,会存在网络多一跳的情况)。

存储层的拆分:按照业务维度做垂直拆分、按照数据特征维度进一步做水平拆分(分库分表)。

业务层的拆分:最常见的是按照业务维度拆(比如电商场景的商品服务、订单服务等),也可以按照核心接口和非核心接口拆,还可以按照请求源拆(比如To C和To B,APP和H5)。

get请求与post请求有什么区别?

16)GET方法和POST方法的区别是什么?

GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

● Get产生一个TCP数据包;Post产生两个TCP数据包。
● GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
● GET请求只能进行url编码,而POST支持多种编码方式。
● GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

  1. GET与POST都有自己的语义,不能随便混用。
  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

GET在浏览器回退时是无害的,而POST会再次提交请求。

GET产生的URL地址可以被Bookmark,而POST不可以。

GET请求会被浏览器主动cache,而POST不会,除非手动设置。

GET请求只能进行url编码,而POST支持多种编码方式。

GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

GET请求在URL中传送的参数是有长度限制的,而POST没有。

对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

GET参数通过URL传递,POST放在Request body中。

  1. GET与POST都有自己的语义,不能随便混用。
  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

Linux简单命令

查看空间,内存

1.free

free命令用于显示内存状态。

free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共享内存区段,以及系统核心使用的缓冲区等。

查询日志

cat 由第一行开始显示文件内容
tac 从最后一行开始显示,可以看出 tac 是 cat 的倒着写!
nl 显示的时候,顺道输出行号!
more 一页一页的显示文件内容
less 与 more 类似,但是比 more 更好的是,他可以往前翻页!
head 只看头几行
tail 只看尾巴几行

#根据文件名查文件路径 -i表示不区分大小写
find -iname “文件名”
#根据关键字查询在文件哪一行(注意关键字与文件名大小写区分)
grep -n 【关键字】 文件名

查端口号

Linux 查看端口占用情况可以使用 lsof 和 netstat 命令。

lsof(list open files)是一个列出当前系统打开文件的工具。

lsof 查看端口占用语法格式:
lsof -i:端口号

netstat -tunlp 用于显示 tcp,udp 的端口和进程等相关情况。

netstat 查看端口占用语法格式:

netstat -tunlp | grep 端口号

mikdir——Make Directory

执行mkdir命令创建相应的文件夹

pwd — Print Working Directory

显示当前工作目录

cd — Change Directory

切换文件路径,cd 将给定的文件夹(或目录)设置成当前工作目录。
切换路径到桌面 desktop

.rmdir— Remove Directory

删除给定的目录

rm— Remove

删除某个文件

cp— Copy

文件的复制

mv— Move

mv 命令对文件或文件夹进行移动,如果文件或文件夹存在于当前工作目录,还可以对文件或文件夹进行重命名。

grep

在给定的文件中搜寻指定的字符串。grep -i “” 在搜寻时会忽略字符串的大小写,而grep -r “” 则会在当前工作目录的文件中递归搜寻指定的字符串。

find

这个命令会在给定位置搜寻与条件匹配的文件。你可以使用find -name 的-name选项来进行区分大小写的搜寻,find -iname 来进行不区分大小写的搜寻。

tar

tar命令能创建、查看和提取tar压缩文件。tar -cvf 是创建对应压缩文件,tar -tvf 来查看对应压缩文件,tar -xvf 来提取对应压缩文件。
查看压缩文件

gzip

gzip 命令创建和提取gzip压缩文件,还可以用gzip -d 来提取压缩文件。
生成gzip文件

2、八股文题目
Java基础
1)为什么Java代码可以实现一次编写、到处运行?
2)一个Java文件里可以有多个类吗(不含内部类)?
3)说一说你对Java访问权限的了解
4)介绍一下Java的数据类型
5)int类型的数据范围是多少?
6)请介绍全局变量和局部变量的区别
7)请介绍一下实例变量的默认值
8)为啥要有包装类?
10)如何对Integer和Double类型判断相等?
11)int和Integer有什么区别,二者在做==运算时会得到什么结果?

14)封装的目的是什么,为什么要有封装?
15)说一说你对多态的理解
16)Java中的多态是怎么实现的?
17)Java为什么是单继承,为什么不能多继承?
18)说一说重写与重载的区别
19)构造方法能不能重写?
20)介绍一下Object类中的方法
集合类
1)Java中有哪些容器(集合类)?
2)Java中的容器,线程安全和线程不安全的分别有哪些?
3)Map接口有哪些实现类?
4)描述一下Map put的过程
5)如何得到一个线程安全的Map?
6)HashMap有什么特点?
7)JDK7和JDK8中的HashMap有什么区别?
8)介绍一下HashMap底层的实现原理
9)介绍一下HashMap的扩容机制
10)HashMap中的循环 链表是如何产生的?
11)HashMap为什么用 红黑树而不用B树?
12)HashMap为什么线程不安全?
13)HashMap如何实现线程安全?
14)HashMap是如何解决哈希冲突的?
15)说一说HashMap和HashTable的区别
16)HashMap与ConcurrentHashMap有什么区别?
17)介绍一下ConcurrentHashMap是怎么实现的?
18)ConcurrentHashMap是怎么分段分组的?
19)说一说你对LinkedHashMap的理解
20)请介绍LinkedHashMap的底层原理
IO
1)介绍一下Java中的IO流
2)怎么用流打开一个大文件?
3)说说NIO的实现原理
4)介绍一下Java的序列化与反序列化
5)Serializable接口为什么需要定义serialVersionUID变量?
6)除了Java自带的序列化之外,你还了解哪些序列化工具?
7)如果不用JSON工具,该如何实现对实体类的序列化?
多线程
1)说一说线程的生命周期
2)说一说线程同步的方式
3)说一说你对volatile关键字的理解
4)说一说synchronized的实现原理
5)创建线程有哪几种方式
JVM
1)说一说你对双亲委派模型的理解
2)介绍一下分代回收机制
3)内存泄漏问题该如何解决
4)内存溢出问题该如何解决
5)JVM包含哪几部分?
框架
1)请描述Spring Boot自动装配的过程
2)说一说你对Spring IoC的理解
3)说一说你对Spring AOP的理解
4)什么是MVC
5)说说你对Spring Boot的理解
Redis
1)说一说Redis的单线程模型
2)缓存穿透、缓存击穿、缓存雪崩有什么区别,该如何解决?
3)说一说你对布隆过滤器的理解
4)说一说hash类型的底层数据结构
5)说一说zset类型的底层数据结构
6)Redis有哪些数据类型
操作系统

3)请你说说 Linux 中 fork() 函数的作用
4)说一说进程调度算法有哪些
5)说一说 Linux 如何管理内存

8)简述一下操作系统中的缺页中断
9)说一说虚拟地址空间有哪些部分
10)什么是孤儿进程,什么是僵尸进程,如何解决僵尸进程
11)说一说进程通信的方式有哪些?
12)说说常见信号有哪些,表示什么含义
13)说一说进程有多少种状态,如何转换
14)介绍一下信号量
15)说一说 select 的原理以及缺点
16)说一说 epoll 的原理
17)介绍一下几种 IO 模型
18)说一说软链接和硬链接的区别
计算机网络
网络模型
OSI七层模型

物理层:网卡,网线,集线器,中继器,调制解调器

数据链路层:网桥,交换机

网络层:路由器

1)TCP/IP四层模型
2)结合OSI模型和TCP/IP模型的五层协议体系结构
3)IP协议的首部结构
4)DNS(域名系统)是什么?

TCP/UDP

TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:

● FTP文件传输
● HTTP / HTTPS

UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:

● 包总量较少的通信,如 DNS 、SNMP等
● 视频、音频等多媒体通信
● 广播通信

1)TCP(传输控制协议)是什么?
2)TCP协议的特点有哪些?
3)TCP协议的首部结构
4)TCP协议三次握手和四次挥手的过程
5)TCP协议是怎么保证有效传输的?
6)TCP协议的流量控制和拥塞控制
7)UDP(用户数据报协议)是什么?
8)UDP协议的特点有哪些?
9)UDP协议的首部结构
10)如何让UDP协议变得可靠?
11)TCP协议和UDP协议的区别是什么?
12)HTTP(超文本传输协议)是什么?
14)常见的HTTP协议状态码有哪些?
状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
● 1xx:指示信息–表示请求已接收,继续处理
● 2xx:成功–表示请求已被成功接收、理解、接受
● 3xx:重定向–要完成请求必须进行更进一步的操作
● 4xx:客户端错误–请求有语法错误或请求无法实现
● 5xx:服务器端错误–服务器未能实现合法的请求

15)HTTP协议的请求方式有哪些?

17)常见的HTTP协议请求头有哪些?
18)常见的HTTP协议响应头有哪些?
HTTP/HTTPS
● HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
● 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
● HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
● http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
● HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,SSL运行在TCP协议之上;所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

HTTP原理HTTP是一个基于TCP/IP通信协议来传递数据的协议,传输的数据类型为HTML 文件,、图片文件, 查询结果等。

HTTP协议一般用于B/S架构()。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。

存在的问题:请求信息明文传输,容易被窃听截取;数据的完整性未校验,容易被篡改;没有验证对方身份,存在冒充危险

HTTP结构
request 请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。
response 状态行、消息报头、空行和响应正文

HTTP 5大特点

  1. 支持客户/服务器模式。
  2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  3. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  4. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。早期这么做的原因是请求资源少,追求快。后来通过Connection: Keep-Alive实现长连接
  5. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):一般理解为HTTP+SSL/TLS,通过 SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密。

HTTPS存在的问题:

● HTTPS协议多次握手,导致页面的加载时间延长近50%;
● HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗;
● 申请SSL证书需要钱,功能越强大的证书费用越高。
● SSL涉及到的安全算法会消耗 CPU 资源,对服务器资源消耗较大。

1)HTTP协议的缓存策略有哪些?
2)HTTPS(安全超文本传输协议)是什么?
3)HTTPS协议如何保证整个传输过程安全?
4)HTTPS协议对称加密的过程?
5)HTTPS协议非对称加密的过程?
6)HTTPS协议中间人攻击是什么?
7)哪些问题是HTTPS无法解决的?
数据库

5)如何判断MySQL中的索引有没有生效
6)说一说InnoDB引擎中索引的实现原理
7)MySQL的ACID特性分别是怎么实现的
8)谈谈MySQL的事务隔离级别
9)谈谈InnoDB引擎中的锁
10)InnoDB中的行级锁是怎么实现的
11)说一说你对MySQL引擎的了解
12)说一说你对redo log、undo log、bin log的了解
14)MySQL主从同步是如何实现的
15)你对MySQL的慢查询优化有了解吗

你可能感兴趣的:(java,面试)