面试知识
2020-05-14 15:15:11 1 举报
AI智能生成
面试题库
作者其他创作
大纲/内容
java
java基础
1. JDK 和 JRE 有什么区别?
JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
2.Java中基本类型和引用类型的区别
基本数据类型(8种)
byte、boolean、char、short、int、float、long、double
引用数据类型
3.== 和 equals 的区别是什么?
== 解读
equals 解读
4.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不对,两个对象的 hashCode()相同,equals()不一定 true
5.final 在 java 中有什么作用?
6.java 中操作字符串都有哪些类?它们之间有什么区别?
String
String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象
Stringbuffer
StringBuffer可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String
StringBuilder
StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String
7.String str="i"与 String str=new String("i")一样吗?
8.如何将字符串反转?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
9.抽象类必须要有抽象方法吗?抽象类能使用 final 修饰吗?
不需要,抽象类不一定非要有抽象方法。
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
10.普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。
11.接口和抽象类有什么区别?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
12.java 中 IO 流分为几种?
按功能来分:输入流(input)、输出流(output)
按类型来分:字节流和字符流
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据
13.BIO、NIO、AIO 有什么区别?
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制
14.Files的常用方法都有哪些?
15.常用数据结构
集合,线性结构(数组,队列,链表和栈),树形结构,图状结构
16.如何创建单例模式?如何高效的创建一个线程安全的单例?
通过枚举实现单列或者静态内部类
通过双重检索
17.java字节码是什么?和我们写的JAVA代码有什么不一样嘛?
计算机可以识别的二进制文件,可以实现一次编译到处运行
java代码编译后才是字节码,可以被计算机识别
18.static属性为什么不会被序列化?
因为序列化是针对对象而言的, 而static属性优先于对象存在, 随着类的加载而加载, 所以不会被序列化
19.实现序列化和反序列化为什么要实现Serializable接口?
在Java中实现了Serializable接口后, JVM会在底层帮我们实现序列化和反序列化, 如果我们不实现Serializable接口, 那自己去写一套序列化和反序列化代码也行
20.千万级数据导出Excel
容器
1.java 常用的容器都有哪些?
Collection
List
ArrayList
如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率
Vector
Stack
LinkedList
Set
TreeSet
HashSet
LinkHashSet
Queue
Collection
PriorityQueue
Map
HashMap
TreeMap
2.Collection 和 Collections 有什么区别?
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
3.List、Set、Map 之间的区别是什么?
4.HashMap 和 Hashtable 有什么区别?
hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。
hashMap允许空键值,而hashTable不允许。
5. 如何决定使用 HashMap 还是 TreeMap?
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择
你需要对一个有序的key集合进行遍历,TreeMap是更好的选择(用红黑树实现的)
6.说一下 HashMap 的实现原理?
HashMap的结构是jdk1.7(数组+链表),jdk1.8+(数组+链表+红黑树)
注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)
Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾(使用头插法).如果数组中该位置没有元素,就直接将该元素放到数组的该位置上
HashMap的初始大小为16,扩容因子0.75,当数组的大小大于16*0.75=12时,会进行扩容,创建一个新的数组,把以前的数据重新计算hash复制到新的数组中,来实现扩容操作(注意扩容时出现链表数据复制时出现死循环)
7.如何处理HastMap使其线程安全
通过Collections.synchronizedMap()返回一个新的Map
重新改写了HashMap,具体的可以查看java.util.concurrent.ConcurrentHashMap
8.ArrayList 和 LinkedList 的区别是什么?
ArrrayList底层的数据结构是数组,支持随机访问
LinkedList 的底层数据结构是双向循环链表,不支持随机访问
ArrayList 查询速度快,插入慢,LinkedList查询速度慢,插入速度快(链表插入的速度很快,他会有指针对应下一个节点,如果插入只要找到指针就可以直接插入数据)
ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)
9.如何实现数组和 List 之间的转换?
List转换成为数组:调用ArrayList的toArray方法。
数组转换成为List:调用Arrays的asList方法。
10.Array 和 ArrayList 有何区别?
Array可以容纳基本类型和对象,而ArrayList只能容纳对象
Array是指定大小的,而ArrayList的大小是动态变化的
Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等
多线程
1.并发编程的作用?
并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
2.线程和进程的区别?
进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。
3.守护线程是什么?
守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程。
4.创建线程有哪几种方式?
继承Thread类创建线程类
通过Runnable接口创建线程类
通过Callable和Future创建线程
使用Executor框架创建线程池
5.线程有哪些状态?
创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪
6.sleep() 和 wait() 有什么区别?
sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象
wait():wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程。
7.创建线程池有哪几种方式?
newFixedThreadPool(int nThreads)
创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。
newCachedThreadPool()
创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。
newSingleThreadExecutor()
这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行。
newScheduledThreadPool(int corePoolSize)
创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
8.在 java 程序中怎么保证多线程的运行安全?
原子性
提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
可见性
一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
有序性
一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)
9.怎么防止死锁?
死锁的四个必要条件
互斥条件
进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
请求和保持条件
进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
不可剥夺条件
是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
环路等待条件
是指进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之 一不满足,就不会发生死锁
在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确 定资源的合理分配算法,避免进程永久占据系统资源
10.ThreadLocal 是什么?有哪些使用场景?
线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java提供ThreadLocal类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险
11.说一下 synchronized 底层实现原理?
普通同步方法,锁是当前实例对象
静态同步方法,锁是当前类的class对象
同步方法块,锁是括号里面的对象
12.synchronized 和 volatile 的区别是什么?
13.(1)线程饥饿是什么?会对我们的系统造成什么影响
如果优先级高的线程一直抢占优先级低线程的资源,导致低优先级线程无法得到执行,这就是饥饿
导致系统资源任务处理分配不均匀
14.线程安全中的可见性问题为什么会出现?怎么解决这类问题
并发的线程能不能看见到变量的最新值,这就是并发中变量的可见性问题。
要让并发中共享变量可见,可以使用synchronized或者volatile
15.Java 中什么是无锁编程?
CAS---比较并交换
AtomicLong、AtomicInteger
16.说一说用多线程实现生产者消费者模型有哪些方式?
1、synchronized+wait+notifyAll
2、ReetrantLock+Condition
3、BlockingQueue实现
事务
1.事务注解@Transactional不起作用的原因总结
事务配置正确的前提下,出现事务不起作用的原因
异常被try{}catch(){}捕捉到了,有异常就不会回滚
当本类的使用@Transactional的方法被本类的其它没有开启事务的方法调用时,不会开启事务。使用@Transactional的方法被其它类调用时,按照正常的事务传播行为规则开启事务
数据库引擎要支持事务
如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的
是否开启了对注解的解析,配置文件必须加<tx:annotation-driven />,否则不解析@Transactional
2.事物的四大特性(ACID)介绍一下?
原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的
隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响
3.什么是脏读?幻读?不可重复读?
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的
架构
Spring
1.Spring 中的设计模式?
BeanFactory和ApplicationContext应用了工厂模式
在Bean的创建过程中,Spring提供了单列和原型等模式
AOP领域使用了代理模式、装饰器模式、适配器模式
事件监听器使用的是观察者模式
类似JdbcTemplate等摸版对象,使用的是摸版模式
SpringMVC
1.SpringMVC的核心组件有哪些?
DispatcherServlet: 作为前端控制器。整个流程控制中心,控制其他组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性
Handler: (Controller)后端控制器,负责处理请求的控制逻辑(业务逻辑)
HandlerMapping: 映射器对象,用于管理url和对应的Controller的映射关系
HandlerAdapter: 适配器,注意处理方法参数、相关注解、数据绑定、消息转换、返回值、调用视图解析器等等
ViewResolver: 视图解析器,解析对应的视图关系
2.SpringMVC的执行流程(实现原理)?
1.一个请求匹配前端控制器DispatcherServlet的请求映射路径
2.DispatcherServlet接收到请求后,将根据请求的信息交给处理映射器(HandlerMapping)
3.HandlerMapping根据请求的url匹配到对应的Handler,并返回一个执行链HandlerExecutionChain
4.DispatcherServlet再请求处理器适配器(HandlerAdapter)调用相应的Handler进行处理并返回ModelAndView给DispatcherServlet
5.DispatcherServlet 将ModelAndView请求ViewReslover(视图解析器)解析,返回具体的View
6.DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
7.DispatcherServlet 将页面响应给用户
3.手写SpringMVC的过程?
1、加载配置文件 spring-config.properties,获取扫描路径
2、扫描配置的路径下的带有注解的类
3、初始化所有的类,被放入到IOC容器中
4、实现@HcAutowried自动注入
5.初始化HandlerMapping,根据url映射不同的controller方法
6.HcDispatcherServlet里面实现doPost方法根据5中的映射关系,根据反射调用invoke方法实现业务调用
实现简单的tomcat
1、封装请求对象MyRequest
获取请求http请求头里面的url和请求方式(post/get)
2、封装响应对象MyResponse
封装返回给前端的数据html页面
3、Servlet 请求处理基类MyServlet
一个抽象接口,提供抽象方法doGet和doPost,还提供一个service方法根据具体的get/post来调用具体的doGet和doPost
4、Servlet 实现类FindGrilServlet
实现抽象方法的doGet和doPost方法,把数据写给前端页面
5、Servlet 配置
ServletMapping.java
url跟servlet包名路径的对应关系实体类
ServletMappingConfig.java
通过静态代码块配置url跟servlet包名路径的关系映射
6.启动类MyTomcatMain
启动socket监听
mysql
1.什么是索引?
索引是一种数据结构(B+Tree)
索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的
2.MYSQL为什么用B+树做索引结构?平时过程中怎么加的索引?
B树体系大量用于文件存储系统,甚至当年的Longhorn的winFS都是基于b树做索引,开源而且好用的也就这么个体系了。B+树的磁盘读写代价更低,便于遍历,查询效率更加稳定,更适合基于范围的查询。数据来了先用索引节点找叶子,叶子找不到就新建叶子加索引书,这样减少io
如何加索引?
1.查询mysql没查询日志语句,通过explain解释执行计划,根据解释计划判断需不需要加索引,那个字段加索引
索引优化有哪些原则:数据类型越小越好,越简单越好,避免空值,最左原则。
一般针对查询比较频繁的字段,关联字段,外联字段需要加索引,查询中排序的字段,统计或者分组字段创建索引,在高并发下倾向创建组合索引,尽量避免表扫描,首先应考虑在where及order by 涉及的列上建立索引;
另外,有一些情况下是不适合建立索引的,如where条件里用不到的字段不用创建索引,1.表记录太少,2.经常增删改的表,3,数据重复且分布平均的表字段,尽量避免在where子句中使用!=或< >或or操作符,否则将放弃引擎而进行全表扫描
一般针对查询比较频繁的字段,关联字段,外联字段需要加索引,查询中排序的字段,统计或者分组字段创建索引,在高并发下倾向创建组合索引,尽量避免表扫描,首先应考虑在where及order by 涉及的列上建立索引;
另外,有一些情况下是不适合建立索引的,如where条件里用不到的字段不用创建索引,1.表记录太少,2.经常增删改的表,3,数据重复且分布平均的表字段,尽量避免在where子句中使用!=或< >或or操作符,否则将放弃引擎而进行全表扫描
3.MyISAM索引与InnoDB索引的区别?
InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效
MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据
InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效
4.mysql添加索引的语句?
ALTER TABLE 表名 ADD 索引类型 (unique,primary key,fulltext,index)[索引名](字段名)
普通索引
ALTER table t_user add INDEX index_name22(age,name);
唯一索引
alter table t_user add unique index_name33(id) ;
主键索引
alter table t_user add primary key (id) ;
全文索引
alter table t_user add fulltext name1222(name)
删除索引
drop index 索引名称 on 表名 ;
5.创建索引的三种方式,删除索引
在执行CREATE TABLE时创建索引
使用ALTER TABLE命令去增加索引
使用CREATE INDEX命令创建
6.创建索引的原则
索引虽好,但也不是无限制的使用,最好符合一下几个原则
1、最左前缀匹配原则,组合索引非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
2、较频繁作为查询条件的字段才去创建索引
3、更新频繁字段不适合创建索引
4、若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
对于那些查询中很少涉及的列,重复值比较多的列不要建立索引
5、尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
6、定义有外键的数据列一定要建立索引
7、对于定义为text、image和bit的数据类型的列不要建立索引
7.使用索引查询一定能提高查询的性能吗?为什么
不一定
通常,通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价
索引需要空间来换取时间,索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能
8.百万级别或以上的数据如何删除
所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
然后删除其中无用数据(此过程需要不到两分钟)
删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。那更是坑了
9.什么是最左前缀原则?什么是最左匹配原则
顾名思义,就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边
最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
10.MySQL的四个隔离级别
READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
Mysql 默认采用的 REPEATABLE_READ隔离级别
SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读
InnoDB 存储引擎在 分布式事务 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。
11、数据库锁有哪些?
行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )
12、MySQL中InnoDB引擎的行锁是怎么实现的?
select * from tab_with_index where id = 1 for update;
for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起
13、数据库的乐观锁和悲观锁是什么?怎么实现的?
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。
14、数据库怎么优化,具体说说
1.优化sql和索引
1.用慢查询日志定位执行效率低的SQL语句
2.用explain分析SQL的执行计划
3.确定问题,采取相应的优化措施,建立索引啊,等
2.搭建缓存
将复杂的、耗时的、不常变的执行结果缓存起来,降低数据库的资源消耗
3.读写分离
利用现成的中间件mycat或者altas等做读写分离
4.分库分表
1.垂直分表
把没有关联的表分到不同的服务器
2.水平分表
把数据量大的表根据关联字段分到不通的服务器
15.慢查询日志
配置项:slow_query_log
可以使用show variables like ‘slov_query_log’查看是否开启,如果状态值为OFF,可以使用set GLOBAL slow_query_log = on来开启,它会在datadir下产生一个xxx-slow.log的文件。
设置临界时间
查看:show VARIABLES like 'long_query_time',单位秒
设置:set long_query_time=0.5
实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉
设置:set long_query_time=0.5
实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉
查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log中
16.为什么要尽量设定一个主键?
主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全。
17.字段为什么要求定义为not null?
null值会占用更多的字节,且会在程序中造成很多与预期不符的情况。
18、SQL语句优化的一些方法?
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描
4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描
5.in 和 not in 也要慎用,否则会导致全表扫描
6.下面的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提高效率,可以考虑全文检索
7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引
19.分布式系统ID生成方案
1. 数据库自增长序列或字段
2. UUID
为了解决UUID不可读,可以使用UUID to Int64的方法
3. Redis生成ID
用Redis的原子操作 INCR和INCRBY来实现
4. Twitter的snowflake算法
5. 利用zookeeper生成唯一ID
6. MongoDB的ObjectId
Mybatis
1.什么是mybatis?
mybatis是一个半自动的ORM(对象映射关系)框架,它内部封装了JDBC,开发只需关注SQL语句的本身,不需要发精力去考虑加载驱动,创建连接的事情上面。
2.#{}和${}的区别?
#{}是预编译处理
在处理#{}时会将sql中的#{}替换为?,调用PreparedStatement的set方法来赋值
使用#{}可以防止sql注入,提高系统安全
${}是字符串替换
在处理${}时直接替换成变量的值
子主题
子主题
子主题
子主题
jvm
消息队列
1.为什么使用消息队列?
消息队列使用的场景和中间件有很多,但解决的核心问题主要是:异步、解耦、消峰填谷
2.消息队列的优缺点
异步、解耦、消峰填谷这是消息队列最大的优点,除了这些消息队列还可以会解决一些我们特殊业务场景的问题
缺点主要在于系统的可用性、复杂性、一致性问题,引入消息队列后,需要考虑MQ的可用性,万一MQ崩溃了岂不是要爆炸?而且复杂性明显提高了,需要考虑一些消息队列的常见问题和解决方案,还有就是一致性问题,一条消息由多个消费者消费,万一有一个消费者消费失败了,就会导致数据不一致
3.如何保证消息队列的高可用?
RabbitMQ
Kafka
4.如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
5.如何保证消息的可靠性传输?(如何处理消息丢失的问题)
生产者弄丢了数据
1.开启 RabbitMQ 事务
RabbitMQ 事务机制(同步)一搞,基本上吞吐量会下来,因为太耗性能
2.cnofirm机制
confirm机制是异步的,你发送个消息之后就可以发送下一个消息,然后那个消息RabbitMQ 接收了之后会异步回调你一个接口通知你这个消息接收到了
RabbitMQ 弄丢了数据
开启 RabbitMQ 的持久化,就是消息写入之后会持久化到磁盘,哪怕是 RabbitMQ 自己挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢
消费端弄丢了数据
刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,RabbitMQ 认为你都消费了,这数据就丢了
关闭 RabbitMQ 的自动ack,处理完成才ack
6.大量消息在mq里积压了几个小时了还没解决
先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉。
新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量。
然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue。
接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据。
这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据。
等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息。
7.消息队列过期失效问题
假设1万个订单积压在mq里面,没有处理,其中1000个订单都丢了,你只能手动写程序把那1000个订单给查出来,手动发到mq里去再补一次。
8.消息队列满了怎么搞?
如果走的方式是消息积压在mq里,那么如果你很长时间都没处理掉,此时导致mq都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上再补数据吧。
9.RabbitMQ 有几种广播类型?
1.fanout: 所有bind到此exchange的queue都可以接收消息(纯广播,绑定到RabbitMQ的接受者都能收到消息);
2.direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息;
3.topic: 所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息;
还有简单模式和工作模式
多线程
锁机制的特性
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。
可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。
synchronized的用法
1、同步方法
(1) 同步非静态方法
(2) 同步静态方法
2、同步代码块
3、修饰对象
Synchronized
CAS(比较和交换)
获取值1,然后修改为2,然后用1跟以前值比较,如果相等就修改结束,如果不相等继续循环读数据,然后修改比较成功为止
Synchronized原理
1.6之前通过虚拟机来进行加锁,需要使用内存进行唤醒,性能低
子主题
锁一共有4种状态
无锁
偏向锁状态
只有一个线程获取这把锁,该锁会偏向这个线程
JVM参数关闭偏向锁
XX:UseBiasedLocking=false,那么程序默认会进入轻量级锁状态
轻量级锁状态
只有一个线程的基础上,另外一个也去拿到这边锁,然后就会升级为轻量锁
重量级锁状态
当前锁为轻量锁时,第二个线程占着锁不放,这是来了第三个线程也来自旋获取锁,这时候会升级为重量锁
AQS和CAS
AQS
给需要获取锁的线程实例出来的一个队列,根据这个队列进行获取锁资源
CAS
0 条评论
下一页