Java面试通关秘籍

基础篇

Java基础

面对对象特征

继承就是子类继承父类的行为,使得子类具有父类的域和方法。继承可以简化代码,提高代码复用性,利于后期维护,但提高了代码的耦合度。

封装是指一种将抽象性函数式接口的实现细节部分包装、隐藏起来的方法。封装可以减少耦合,提高代码复用性。

多态是同一个行为具有多个不同表现形式或形态的能力。多态可以消除类型之间的耦合关系,具有可替换性、可扩充性、接口性、灵活性和简化性。多态存在的三个必要条件是:继承、重写和父类引用指向子类对象。多态实现的三种方式:重写、接口、抽象类和抽象方法。

final、finally和finalize的区别

final声明一个常量。如果一个变量被声明为final,这个变量的值不能被改变,且必须初始化时必须设置值。如果一个方法被声明为final,这个方法不能被重写。如果一个类被声明为final,这个类不能被继承。

finally是try catch语句中来执行清除操作的,无论发生任何情况,都会执行finally中的语句。若try中有return,回先执行finally中的语句再return。

finalize是一个方法名,finalize()方法在Java的垃圾收集器将对象清除出去之前执行。

Exception、Error、运行时异常与一般异常有何异同

所有的异常都继承自Throwable类。

Error类描述了Java运行时系统的内部错误和资源耗尽错误。此种异常不应该由程序抛出,若出现这种异常,应通告给用户并尽力使程序安全地终止。

Exception类是应用程序抛出的错误。Exception类包括IO异常和运行时异常。

RuntimeException类包括错误的类型转换、数组访问越界和访问null指针。在程序中应该杜绝此类异常的发生。

IOException类包括试图在文件尾部后面读取数据、试图打开一个不存在的文件和试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在。此类异常需要在程序中手动抛出。

请写出5种常见到的runtime exception

  • ClassCastException - 错误的类型转换
  • IndexOutOfBoundsException - 数组访问越界
  • NullPointerException - 空指针
  • IllegalArgumentException - 非法参数异常
  • ArithmeticException - 算数运算异常

int 和 Integer 有什么区别,Integer的值缓存范围

  • int是基本数据类型,Integer是int的包装类。

  • int类型的默认值是0,Integer类型的默认值是null。

Integer的值缓存范围:[-128, 127]。

包装类,装箱和拆箱

Java语言虽然是面向对象编程,但是八种基本类型不具备对象的特性,不携带属性,没有方法可调用。所以Java为每种基本类型设计了对应的包装类。

由基本类型向对应的包装类转换称为装箱,由包装类向对应的基本类型转换称为拆箱。

1
2
3
4
Integer a = new Integer(1); // 手动装箱
int b = a.intValue(); // 手动拆箱
Integer c = b; // 自动装箱,Integer var3 = Integer.valueOf(var2);
int d = c; // 自动拆箱,int var4 = var3.intValue();

String、StringBuilder、StringBuffer

  • String是常量,StringBuilder和StringBuffer是变量,运行效率:StringBuilder > StringBuffer > String。
  • String和StringBuffer是线程安全的,StringBuilder是线程不安全的。

重载和重写的区别

重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。

重载是在一个类里面,方法名字相同,而参数不同,返回类型可以相同也可以不同。

重载是一个类的多态性表现,重写是子类与父类的多态性表现。

重写规则:

  • 参数列表必须完全与被重写方法的参数相同。
  • 返回类型必须完全与被重写方法的返回类型相同。
  • 访问权限不能比父类中被重写的方法的访问权限更低。
  • 父类的成员方法只能被它的子类重写。
  • 声明为final的方法不能被重写。
  • 声明为static的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final的方法。
  • 重写的方法能够抛出任何非可查异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的可查异常,或者比被重写方法声明的更广泛的可查异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个方法,则不能重写这个方法。

重载规则:

  • 被重载的方法必须改变参数列表(参数个数或类型不一样)。
  • 被重载的方法可以改变返回类型。
  • 被重载的方法可以改变访问修饰符。
  • 被重载的方法可以声明新的或更广的可查异常。
  • 方法能够在同一个类中或者在一个子类中被重载。
  • 无法以返回值类型作为重载函数的区分标准。

抽象类和接口有什么区别

参数 抽象类 接口
默认的方法实现 可以有默认的方法实现 可以有方法的实现
实现 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,需要提供抽象类中所有抽象方法的实现。 子类使用关键字implements来实现接口,需要提供接口中所有普通方法的实现。
构造器 可以有构造器 不可以有构造器
与正常Java类的区别 不能实例化抽象类 完全不同于Java类
访问修饰符 抽象方法可以有public、protected和default 方法默认是public
多继承 可以继承一个类和多个接口 可以继承多个接口
速度 比接口快 较慢,需要时间寻找在类中实现的方法

说说反射的用途及实现

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法,这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

Java反射框架提供以下功能:

  1. 在运行时判断任意一个对象所属的类。
  2. 在运行时构造任意一个类的对象。
  3. 在运行时判断任意一个类所具有的成员变量和方法(通过反射设置可以调用private)。
  4. 在运行时调用任意一个对象的方法。

反射的主要用途就是开发各种通用框架,如Spring的IOC,JavaBean和jsp之间的调用,JDBC的classForName()等等。

获取一个对象的反射类:

  1. 通过getClass()方法。
  2. 通过Class.firName()方法。
  3. 使用类.class。

反射获取对象实例:

  1. 直接使用Class对象的newInstance()方法。
  2. 使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法。

说说自定义注解的场景及实现

Java有四种元注解:@Retention、@Inherited、@Documented、@Target

注解的用处:

  1. 生成文档,如@param、@return等。
  2. 跟踪代码依赖性,实现替代配置文件功能。
  3. 在编译时进行格式检查。
  4. 类属性自动赋值。

HTTP请求的GET与POST方式的区别

GET POST
点击返回/刷新按钮 没有影响 数据会重新发送(浏览器将会提示用户“数据被重新提交”)
添加书签 可以 不可以
缓存 可以 不可以
编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded or multipart/form-data. 请为二进制数据使用multipart编码
历史记录 没有
长度限制 没有
数据类型限制 只允ASCII字符类型 没有限制,允许二进制数据
安全性 不安全 数据不会显示在地址栏中,也不会缓存下来或保存在浏览记录里,比较安全
可见性 查询字符串显示在地址栏的URL中,可见 查询字符串不会显示在地址栏中,不可见

Session与Cookie区别

  1. session数据存储在服务端,cookie数据存储在客户端。
  2. session的大小限制与服务器的内存大小有关,cookie有大小限制和个数限制。
  3. cookie有安全隐患,通过拦截或本地文件找到cookie后可以进行攻击。
  4. session在服务器端保存一段时间才会销毁,如果session过多会增加服务器端压力。

列出自己常用的JDK包

java.lang—系统基础类,如String、Math、Integer、System、Thread等。

java.io—输入输出有关的类,如文件操作。

java.net—网络有关的类,如URL、URLConnection等。

java.util—系统辅助类,如Collection、List、Map等。

java.sql—数据库操作类,如Connection、Statement、ResultSet等。

MVC设计思想

MVC——Model 模型、View视图和Controller控制器,模型就是封装业务逻辑和数据的一个一个的模块,控制器负责视图与模型的交互,视图就是看到的页面。

equals与==的区别

基本数据类型使用==来判断是否相等。对象一般使用equals来判等,若对象使用==符号,判断的是对象的引用指向的地址是否是同一个。equals方法默认比较的是对象的地址,但是类一般会重写equals方法,使对象比较内容是否相等。

hashCode和equals方法的区别与联系

hashCode方法返回对象的哈希值,equals方法比较两个对象是否相等,返回true或false。

hashCode主要是为了HashMap等比较对象的相等性,是为了解决使用equals比较相等性效率低的问题。

在没有修改equals方法的情况下,相同的对象返回的hashCode值一定相等。 如果两个对象equals方法返回true,那么在这两个对象的hashCode值一定相等。如果两个对象equals方法返回false,那么不能保证这两个对象的hashCode值不相等,但是我们必须意识到,返回hashCode值不同的话会提升HashMap的效率。

所以在我们的日常开发中,如果一个类重写了equals方法,也应该重写hashCode方法,保持两个方法的一致性。

什么是Java序列化和反序列化,如何实现Java序列化?或者请解释Serializable 接口的作用

序列化是将Java对象转为字节序列,反序列化是将字节序列转为Java对象。

类继承Serializable接口,使用ObjectOutputStream的writeObject方法就可以进行序列化,使用ObjectInputStream的readObject方法就可以进行反序列化。

Serializable接口只是一个标志性接口,接口中没有任何变量和方法。实现Serializable接口的类就可以进行序列化。

Object类中常见的方法,为什么wait notify会放在Object里边?

常见方法——hashCode()、equals()、toString()、clone()。

wait()、notify()、notifyAll()这三个方法存在于同步中,在调用这三个方法时必须标识同步所属的锁,锁可以是任意对象,所以任意对象调用方法一定定义在Object类。

Java的平台无关性如何体现出来的

Java程序通过一次编译,就可以在多个平台运行。各种不同平台的虚拟机与所有平台都统一使用的程序存储格式–字节码是构成平台无关性的基石,字节码是与平台无关的,任何虚拟机都可以载入和执行字节码来实现“一次编译,到处运行”。

JDK和JRE的区别

JDK,英文Java Development Kit,是针对Java开发人员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。

JRE,英文Java Runtime Environment,是运行Java程序所必须的环境的集合,包含JVM标准实现及Java核心类库。

JVM,Java Virtual Machine,是整个Java实现跨平台的最核心的部分,能够运行以Java语言编写的软件程序。

Java 8有哪些新特性

  1. Lambda表达式
  2. 方法引用
  3. 函数式接口
  4. 默认方法和静态方法
  5. Stream
  6. Optional类
  7. Nashorn JavaScript
  8. 日期时间API
  9. Base64

Java常见集合

List和Set区别

  1. List中元素有序,Set中元素无序。
  2. List中元素可重复,Set中元素不可重复。

Set和hashCode以及equals方法的联系

向Set中存放元素时,先调用hashCode方法获取它的哈希值,通过哈希值定位到放置的位置。如果这个位置没有元素就直接存储在这个位置上,如果这个位置有元素,先调用equals方法比较两个元素是否相等,相同的话就不存了,不同的话就散列其他的位置。

如果两个对象相同,那么它们的hashCode值一定相同;如果两个对象不同,那么它们的hashCode值不一定不同。所以在平时的开发中,一定要保证hashCode方法和equals方法的一致性,当equals方法判断不相等时,hashCode方法一定要不相等,当equals方法判断不相等时,hashCode方法要尽量避免相等。

List和Map区别

  1. List是存储单列数据的集合,Map是存储键值的双列数据的集合。
  2. List中存储的数据有序,并且允许重复,Map中存储的数据无序,键不能重复,值可以重复。

Arraylist 与 LinkedList 区别

  1. ArrayList是基于动态数组,LinkedList基于链表。
  2. 对于随机访问get和set,ArrayList优于LinkedList。
  3. 对于新增和删除add和remove,LinkedList优于ArrayList。
  4. ArrayList和LinkedList都存在空间浪费现象,ArrayList主要体现在list的结尾会预留一定的容量空间,LinkedList主要体现在每一个元素都要存储它的上一个元素和下一个元素。

ArrayList 与 Vector 区别

  1. 同步性:Vector的所有方法都使用了同步锁,是线程安全的,ArrayList是线程不安全的。
  2. 容量扩展机制:Vector扩展指定增量或者1倍,ArrayList扩展0.5倍。

HashMap 和 HashTable 的区别

  1. HashMap采用数组+链表+红黑树的数据结构,HashTable采用数组+链表的数据结构。
  2. HashMap扩容为原来容量的2倍,HashTable扩容为原来容量的2倍加1。
  3. HashMap的键和值都可以为null,HashTable的键和值都不可以为null。
  4. HashMap是线程不安全的但是效率比较高,HashTable是线程安全的但是效率比较低。

HashSet 和 HashMap 区别

  1. HashMap实现了Map接口,HashSet实现了Set接口。
  2. HashMap存储键值对,HashSet存储对象。
  3. HashMap调用put()方法向map中添加元素,HashSet调用add()方法向set中添加元素。
  4. HashMap使用key计算hashCode,HashSet使用对象来计算hashCode。
  5. HashMap相比较快,它使用唯一的键来获取对象,HashSet比较慢。

HashMap 和 ConcurrentHashMap 的区别

  1. ConrrentHashMap对整个桶数组进行了分割分段,然后在每一个分段上都用lock锁进行保护,相对于HashTable的syn关键字锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。
  2. HashMap的键和值允许有null,但是ConcurrentHashMap的键和值都不允许有null。

HashMap 的工作原理及代码实现,什么时候用到红黑树

HashMap采用数组+链表+红黑树的数据结构。通过键值的哈希值映射到数组的某个位置,如果发生哈希碰撞,就放在链表的末尾。当链表长度等于8并且数组容量大于最小树化容量时,链表转化为红黑树。

多线程情况下HashMap死循环的问题

JDK1.8之前,HashMap进行扩容之后的table复制时,会将元素添加在链表的头端,两个线程同时进行扩容操作,会导致链表闭环,导致get操作死循环。但是JDK1.8解决了这个问题,改为在链表末尾添加元素,resize之后链表顺序不会发生变化,也就不会出现环形链表。但是JDK1.8的HashMap存在数据丢失等的问题。

ConcurrentHashMap 的工作原理及代码实现,如何统计所有的元素个数

看过那些Java集合类的源码

  1. ArrayList和LinkedList
  2. HashMap、HashTable和LinkedHashMap

进程和线程

线程和进程的概念、并行和并发的概念

进程是表示资源分配和调度运行的基本单位。

线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。

并发:时间段内有很多的线程或进程在执行,但任何时间点上都只有一个在执行,多个线程或进程争抢时间片轮流执行。

并行:时间段和时间点上都有多个线程或进程在执行。

单核CPU只能并发,多核CPU才能做到并行执行。

创建线程的方式及实现

  1. 继承Thread类创建线程类。
  2. 通过Runnable接口创建线程类。
  3. 通过Callable和Future创建线程。

详细参考Java创建线程的三种方式

sleep()、join()、yield()有什么区别

sleep()方法让线程在指定时间内休息,可以让其他线程得到运行的机会,当休息时间达到指定之间,线程立马重新开始运行。与Object的wait()方法不同的是,sleep()方法在休息期间并不会释放掉锁,但是wait()方法会让线程释放掉对象的锁。

join()方法让指定的线程先执行完在执行其他线程,而且会阻塞主线程。join()方法也不会释放掉锁。

yield()方法会先让相同优先级或更高优先级的线程执行,yield()方法也不会释放资源的锁。

详细参考Thread的几种状态以及sleep/yield/join/wait/notify/notifyAll方法的区别

进程间通信的方式

  1. 管道

    管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

  2. 命名管道

    命名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

  3. 信号

    信号是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生。

  4. 消息队列

    消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号量传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

  5. 共享内存

    共享内存就是映射一段能被其它进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

  6. 信号量

    信号量是一个计数器,可以用来控制多个进程对共享资源的访问,它常作为一种锁机制,防止某进程正在访问共享资源时,其它进程访问该资源,因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

  7. 套接口

    套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

说说 CountDownLatch、CyclicBarrier 原理和区别

CountDownLatch:一个线程(或多个线程)等待另外N个线程完成某个事情之后才能执行。

CyclicBarrier:N的线程互相等待,任何一个线程完成之前,所有的线程都必须等待。

区别:

  1. CountDownLatch是减计数,CyclicBarrier是加计数。
  2. CountDownLatch是一次性的,CyclicBarrier可以重用。
  3. CountDownLatch的重点是那一个线程(或多个线程),是它(们)在等待,另外N个线程在把某个事情做完之后,可以继续,可以终止。CyclicBarrier的重点是那N个线程,N个线程互相等待。

说说 Semaphore 原理

Semaphore限定一个资源的访问的线程数量,当访问线程数量超过设定数量时,就阻塞一部分线程,直到有线程师范资源。

说说 Exchanger 原理

Exchanger让两个线程互换数据,当一个线程调用exchange方法时如果没有另一个线程的exchange方法,就阻塞等待另一个线程的exchange方法,然后两者互选数据,之后两个线程进入就绪状态。

ThreadLocal 原理分析,ThreadLocal为什么会出现OOM,出现的深层次原理

讲讲线程池的实现原理

线程池的几种实现方式

  1. 使用Java的Executors类创建。
  2. 手动创建ThreadPoolExecutor。
  3. 使用Spring的ThreadPoolTaskExecutor。

线程的生命周期,状态是如何转移的

操作系统的进程调度算法

  1. 先来先服务(FCFS)

    作业名 到达时间 服务时间 开始时间 完成时间
    1 8 2 8 10
    2 8.5 0.5 10 10.5
    3 9 0.1 10.5 10.6
    4 9.5 0.2 10.6 10.8

    FCFS是非抢占式的,易于实现,效率不高,性能不好,有利于长作业(CPU频繁性)而不利于短作业(I/O繁忙性)。

  2. 最短剩余时间优先(SJF)

    作业名 到达时间 服务时间 开始时间 完成时间
    1 8 2 8 10.8
    2 8.5 0.5 8.5 9
    3 9 0.1 9 9.1
    4 9.5 0.2 9.5 9.7

    SJF是抢占式的,由于频繁地抢占和进程切换,系统开销大,该算法实现代价高,一般用于实时系统。

  3. 高响应比优先(HRRF)

    响应比 = (等待时间 + 服务时间) / 服务时间

    作业名 到达时间 服务时间 开始时间 完成时间
    1 8 2 8 10
    2 8.5 0.5 10.1 10.6
    3 9 0.1 10 10.1
    4 9.5 0.2 10.6 10.8

    HRRF是非抢占式的,该算法结余FCFS和SJF之间,但每次需要计算每个作业的响应比,增加系统开销。

  4. 优先级

    每次挑选优先级最高的一个或多个调入,分为抢占式和非抢占式。

  5. 时间片轮转

    作业名 到达时间 服务时间 开始时间 完成时间
    A 0 3 0 3
    B 1 6 3 19
    C 2 4 7 11
    D 3 5 11 20
    E 4 2 15 17

    该算法简单有效,常用于分时系统,但不利于I/O频繁而紧凑的,由于这种进程用不完一个时间片,就因为等待I/O操作而被阻塞,当I/O操作结束后,只能插入到就绪队列的末尾,等待下一轮调度。

锁机制

说说线程安全问题,什么是线程安全,如何保证线程安全

重入锁的概念,重入锁为什么可以防止死锁

产生死锁的四个条件(互斥、请求与保持、不剥夺、循环等待)

如何检查死锁(通过Console检查死锁)

volatile实现原理(禁止指令重排、刷新内存)

synchronized实现原理(对象监视器)

synchronized与lock的区别

AQS同步队列

CAS无锁的概念、乐观锁和悲观所

常见的原子操作类

什么是ABA问题,出现ABA问题JDK是如何解决的

乐观锁的业务场景及实现方式

Java 8并发包下常见的并发类

偏向锁、轻量级锁、重量级锁、自旋锁的概念

JVM

JVM运行时内存区域划分

内存溢出OOM和堆栈溢出SOE的示例及原因、如何排查与解决

如何判断对象是否可以回收会存活

常见的GC回收算法及其含义

常见的JVM性能监控和故障处理工具类:jps、jstat、jmap、jinfo、jconsole等

JVM如何设置参数

JVM性能调优

类加载器、双亲委派模型、一个类的生命周期、类是如何加载到JVM中的

类加载的过程:加载、验证、准备、解析、初始化

强引用、软引用、弱引用、虚引用

Java内存模型JMM

设计模式

常见的设计模式

设计模式的六大原则及其含义

常见的单例模式以及各种实现方式的优缺点,哪一种最好,手写常见的单例模式

设计模式在实际场景中的应用

Spring中用到了哪些设计模式

Mybatis中用到了哪些设计模式

你项目中有使用哪些设计模式

说说常用开源框架中设计模式使用分析

动态代理

数据结构

树(二叉查找树、平衡二叉树、红黑树、B树、B+树)

深度优先算法、广度优先算法

克鲁斯卡尔算法、普林母算法、迪克拉斯算法

什么是一致性Hash及其原理、Hash环问题

常见的排序算法和查找算法:快排、折半查找、堆排序等

网络/IO基础

BIO、NIO、AIO的概念

什么是长连接和短连接

HTTP1.0和2.0相比有什么区别

HTTPS的基本概念

三次握手和四次挥手,为什么挥手需要四次

从浏览器中输入URL到页面加载的发生了什么

数据存储和消息队列

数据库

MySQL索引使用的注意事项

  1. 索引的字段必须是经常作为查询条件的字段。
  2. 如果索引多个字段,第一个字段要是经常作为查询条件的,如果只有第二个字段作为查询条件,这个索引不会起到作用。
  3. 索引的字段必须有足够的区分度。
  4. MySQL对于长字段支持前缀索引。
  5. MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。
  6. 尽量不要写!=或者<>的sql,用between或> and <代替,否则可能用不到索引。
  7. Order by 、Group by 、Distinct 最好在需要这个列上建立索引,利于索引排序。
  8. 尽量利用mysql索引排序。
  9. 没办法的情况下,使用强制索引Force index(index_name)。
  10. 尽量避勉innodb用非常大尺寸的字段作为主键。
  11. 较频繁的作为查询条件的字段应该创建索引。
  12. 选择性高的字段比较适合创建索引。
  13. 作为表关联字段一般都需要创索引。
  14. 更新非常频繁的字段不适合创建索引。
  15. 不会出现在 WHERE 子句中的字段不该创建索引。
  16. 选择性太低的字段不适合单独创建索引。

DDL、DML、DCL分别指什么

explain命令

left join,right join, inner join

数据库事务ACID(原子性、一致性、隔离性、持久性)

  1. 原子性

    原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。例子:A给B转账,A的账户减钱,B的账户加钱,两个操作要么全部成功,要么全部失败。

  2. 一致性

    一致性是指事务必须是数据库从一个一致性状态变换到另一个一致性状态,也就是说事务执行之前和执行之后都必须处于一致性状态。例子:A和B的钱一共是5000,无论A和B之间如何转账,钱一共还是5000。

  3. 隔离性

    隔离性是当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要互相隔离。

  4. 持久性

    持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

脏读、幻读、不可重复读

  1. 脏读是指一个事务处理过程里读取了另一个未提交的事务中的数据。
  2. 不可重复读是指对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
  3. 幻读是事务非独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么以后就会发生,操作第一个事务的用户发现表中还有没有修改的数据行,就好像发生了幻觉一样。

不可重复读和脏读的区别:

脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

幻读和不可重复读的区别:

幻读和不可重复读都是读取了另一条已经提交的事务,不同的是不可重复读查询的是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

事务的隔离级别

脏读 不可重复读 幻读
未提交读(Read uncommitted) 可能 可能 可能
已提交读(Read committed) 不可能 可能 可能
可重复读(Repeatable read) 不可能 不可能 可能
可串行化(Serializable) 不可能 不可能 不可能

数据库的几大范式

  1. 第一范式(1NF)

    强调的是列的原子性,即列不能够再分成其他几列。

  2. 第二范式(2NF)

    首先满足1NF,然后表必须有一个主键,最后没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。

  3. 第三范式(3NF)

    首先满足2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。

数据库常见的命令

说说分库与分表设计

分库与分表带来的分布式困境与应对之策(如何解决分布式下的分库分表,全局表)

分库分表带来的问题:

  1. 事务的支持就变成了分布式事务。
  2. join时需跨库跨表。
  3. 分布式为了保证强一致性,必然带来延迟,导致性能降低,系统的复杂度变高。

常用的解决方案:

  1. 对于不同的方式之间没有严格的界限,特点不同,侧重点不同。需要根据实际情况,结合每种方式的特点来进行处理。
  2. 选用第三方的数据库中间件(Atlas,Mycat,TDDL,DRDS),同时业务系统需要配合数据存储的升级。

说说SQL优化之道

一. 数据库设计

  1. 适度的反范式
  2. 适当建立索引
  3. 对表进行水平划分
  4. 对表进行垂直划分
  5. 选择适当的字段类型,特别是主键
  6. 文件、图片等大文件用文件系统存储,不用数据库
  7. 外键表示清楚,方便建立索引
  8. 掌握表的写入时机
  9. 宁可集中批量操作,避免频繁读写
  10. 选择合适的引擎

二. SQL语句优化

  1. SQL语句优化工具
  2. Explain
  3. 全索引扫描

三. 数据库参数配置

四. 合理的硬件资源和操作系统

  1. 读写分离

MySQL遇到的死锁问题、如何排查与解决

存储引擎的InnoDB与MyISAM区别,优缺点,使用场景

不同 MyISAM InnoDB
存储结构 每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。 所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。
存储空间 可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。 需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
可移植性、备份及恢复 数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。 免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。
事务支持 强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。 提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
AUTO_INCREMENT 可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,他可以根据前面几列进行排序后递增。 InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。
表锁差异 只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。 支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
全文索引 支持 FULLTEXT类型的全文索引 不支持FULLTEXT类型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。
表主键 允许没有任何索引和主键的表存在,索引都是保存行的地址。 如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。
表的具体行数 保存有表的总行数,如果select count(*) from table;会直接取出出该值。 没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。
CURD操作 如果执行大量的SELECT,MyISAM是更好的选择。 如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令。
外键 不支持 支持

索引类别(B+数索引、全文索引、哈希索引)、索引的原理

什么是自适应哈希索引(AHI)

为什么要用B+树作为MySQL索引的数据结构

聚焦索引与非聚焦索引的区别

遇到过索引失效的情况没,什么时候可能会出现,如何解决

limit 20000 加载很慢怎么解决

如何选择合适的分布式主键方案

选择合适的数据存储方案

常见的几种分布式ID的设计方案

常见的数据库优化方案,在你的项目中数据库如何进行优化的

-------------本文结束感谢您的阅读-------------

本文标题:Java面试通关秘籍

文章作者:huihui

发布时间:2018年07月05日 - 00:07

最后更新:2019年02月14日 - 19:02

原始链接:http://101.200.47.120:8011/2018/07/05/Java面试通关秘籍/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。