1.sql中有select,from,where,group by,order by,having请问sql执行时的顺序是怎样的?答:前面从from(表)where(按条件取出数据)group by(再对取出的数据分组)having(分组后再过滤得到最新数据集)select(按照设置列从数据集里面去除数据)order by(对取出的数据进行排序)执行顺序:from--where--group by--having--select--order by
2.mybatis中resultMap和resultType的区别?答:resultMap更强大一些,可自定义字段为别名(column: 库表的 字段名,property: 实体类里的属性名 );一对多的情况时使用resultMapresultType是实体类和数据库表字段一一对应,直接返回类型。二者不可同时存在
3.hashMap和hashTable有哪些区别?答:hashMap(jdk1.8采用 数组+链表+红黑树,链表阈值长度超过8转为红黑树):1.key-value存储,单链表超出阈值自增;2.线程不安全,适用于单线程(多线程下可能会产生死锁),多线程建议使用concurrent并发包下的concurrentHashMap(分段锁);3.可以有一个null的key,可以有多个null的value;(使用containsKey()方法进行判断是否存在某个键)4.效率高hashTable:1.key-value存储,单链表超出阈值自增;2.线程安全,适用于多线程,因为hashTable每个方法都加了Synchronize;3.key不可为null,value不可为null;4.效率低
4.Bean的生命周期?答:1.实例化bean对象(通过构造方法或工厂方法)2.设置对象属性(setter,依赖注入等)3.如果Bean实现了BeanNameWare接口,工厂调用Bean的setBeanName()方法传递Bean的id。(和下面一条均属于检查Ware接口)4.如果Bean实现了BeanFactoryAware接口,工厂调用BeanFactoryAware()方法传入工程自身5.将Bean实例传递给Bean的前置处理器postProcessBeforeInitialization(Object bean, String beanName)方法6.调用Bean的初始化方法7.将Bean实例传递给Bean的后置处理器postProcessAfterInitialization(Object bean, String beanName)方法8.使用Bean9.容器关闭之前,调用Bean的销毁方法;(简单描述:实例化--设置属性--检查ware接口--初始化--使用--销毁)
5.事务的四大特征?脏读,幻读,不可重复读?答:1.(Atomicity)原子性:要么全成功,要么全失败2.(Isolation)隔离性:多个并发事务互不影响3.(Consistency)一致性:事务前后数据的完整性始终保持一致4.(Durability)持久性:当事务完成后,数据库的改变是永久的5.脏读:读取未提交数据6.幻读:前后多次读取,数据总量不一致7.不可重复读:前后多次读取,数据内容不一致
6.跨域怎么解决?当前端页面与后台运行在不同的服务器时,就必定会出现跨域这一问题。所谓同源策略是指,域名,协议,端口均相同;不同源则产生跨域。答:1.使用ajax的jsonp,该方式只适用于GET请求2.使用negix的反向代理3.使用Cros(在后台控制层加上:@CrossOrigin(origins = "*", maxAge = 3600)//origins : 允许可访问的域列表,"*"代表所有;maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。)
7.IOC和AOP可以说一下嘛?答:IOC控制反转:将创建对象的权利交给核心容器(由容器来负责对象的生命周期和对象之间的关系)。IOC主要实现方式有两种:依赖注入和控制反转(DI:就是IOC容器把当前对象所需要的外部资源动态注入给我们;四种注入方式:注解注入,set注入,构造器注入,静态工厂注入)----当某个角色 需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中 创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者 因此也称为依赖注入。 AOP面向切面编程:可以说是OOP的补充和完善,OOP引入封装、继承和多态性等概念来建立一种对象层次结构。实现AOP的技术,主要分为两大类:一是采用动态代理技术,二是采用静态织入的方式。----这玩意我举个例子说下,比如你写了个方法用来做一些事情,但这个事情要求登录用户才能做,你就可以在这个方法执行前验证一下,执行后记录下操作日志,把前后的这些与业务逻辑无关的代码抽取出来放一个类里,这个类就是切面(Aspect),这个被环绕的方法就是切点(Pointcut),你所做的执行前执行后的这些方法统一叫做增强处理(Advice)。
8.过滤器和拦截器的区别简单说一下
答:过滤器:通俗的说过滤器就是筛选出你想要的东西(就是一堆请求过来时,过滤掉一些不合法的请求),比如request中你想要的那部分,依赖于servlet容器。(应用场景:URL级别的权限访问控制;过滤敏感词汇(防止sql注入);设置字符编码)springboot自定义过滤器实现步骤:1.利用@WebFilter创建Filter过滤器类;2.Application启动类添加@ServletComponentScan注解拦截器:拦截器,请求的接口被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略(底层是动态代理-反射)。 拦截器主要用来按照指定规则拒绝请求。在做安全方便用的比较多,比如终止一些流程等(应用场景:Token令牌验证;请求数据校验;用户权限校验;放行指定接口;拦截未登录用户)。springboot自定义拦截器实现只需两步:1.自定义拦截器,实现HandlerInterceptor这个接口;2.注册拦截器。从灵活性上说拦截器功能更强大些,Filter能做的事情,他都能做;
9.HashMap组成原理和底层实现原理?答:在Java中最基本的数据结构有两种,数组和链表数组:查询快,根据索引查询,添加和删除比较困难;链表:查询慢,需要遍历整个链表,添加和删除容易;HashMap是由数组加链表组成,数据结构中又叫 “链表散列”红黑树(jdk1.8):一种二叉树,高效的检索效率当链表达到一定长度后,链表就会变成红黑树(A下面有两个节点BC,B和C下面又有DEF)HashMap的特点:1.快速存储:比如当我们对hashmap进行get和put的时候速度非常快;
2.快速查找:当我们通过key去get一个value的时候时间复杂度非常的低,效率非常高;
3.可伸缩:1数组扩容,边长。2,单线列表如果长度超过8的话会变成红黑树。
10.微服务架构有了解吗?(比如springCloud)答:(可以说一下springCloud的五大组件,把你知道的都说出来)Eureka:服务注册中心(类似注册中心还有Consul,了解哪一种就描述哪一种)Ribbon:本地负载均衡(Feign:服务与服务间远程调用)Zuul/Gateway:服务网关(类似Nginx反相代理的功能;Gateway是基于Springboot2.0,取代Zuul)Hystrix:断路器Spring Cloud Config:分布式配置(目前还是静态的,需要配合Spring Cloud Bus来实现动态的配置更新)
12.微服务动态配置有几种实现方式?答:1.使用Consul做注册中心,(微服务配置做在线配置统一管理,也可实现动态配置加载);2.携程的Apollo(推荐使用,配置修改实时生效(热发布));3.springCloud全家桶自带的config(听说不是很好用,目前项目中还未用到);4.阿里的 Nacos(即可做服务注册中心,也可做配置中心,听朋友说好用)
13.mysql优化常用到的几种方式,简单说一下?答:mysql优化主要分为以下四大方面:1.设计:存储引擎,字段类型,范式与逆范式,减少访问数据库的次数
2.功能:索引,缓存,分区分表。
3.架构:主从复制,读写分离,负载均衡。
4.合理SQL:合理使用join,尽量不要使用select *,in,not in ,or。
14.spring和springboot的区别(优缺点)答:springboot基本上是spring框架的一个扩展,消除了spring的一些复杂配置
14.Redis用过吗?答:用过,支持多种存储类型,五大基本类型说一下String(字符串):一个key对应一个valueHash(哈希):类似java中Map 常用List(列表):字符串列表Set(集合):String类型的无序集合ZSet:不可重,有序集合说一个使用场景:手机号验证码登录功能,session共享。
15.使用过什么中间件?答:RabbitMQ(消息队列)
MyCat(分库分表,读写分离)
Mybatis(持久层框架)
Swagger2(swagger-ui,Rest APIs文档生成工具)
PageHelper(物理分页插件)
16.请说一下Java中的NIO,BIO,AIO分别是什么?答:BIO:同步阻塞式IO,简单理解:一个连接一个线程,BIO适用于连接数目比较小且固定的架构,这种方式对服务器的资源要求比较高,并发局限于应用中,jdk1.4以前唯一的选择,单程序直观简单易理解。NIO:同步非阻塞IO,简单理解:一个请求一个线程,NIO适合连接数目多且连接比较短(清操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,jdk1.4开始支持。AIO:异步非阻塞IO,简单理解:一个有效请求一个线程,AIO适用于连接数目多,且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,jdk1.7开始支持。
17.说一下Spring的设计模式答:工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;单例模式:Bean默认为单例模式;代理模式:Spring的AOP就是使用了JDK的动态代理和CGLIB字节码生成技术;模版方法:用来解决重复代码的问题,比如RedisTemplate, JpaTemplate。观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。
18.用过那些前端框架?答:Bootstarp;easyUI;LayUIThymeleaf(springboot默认是不支持jsp的,默认使用的Thymeleaf模版引擎)
19.ThreadLocal有什么作用?答:waitingThreadLocal是创建线程的本地变量,一个对像的所有线程共享它的全部局变量,所以这些变量是非线程安全的,我们可以使用同步技术。但是我们不想使用同步技术的时候,可以选择ThreadLocal变量。每个线程都会拥有他们自己的Thread变量,他们可以使用get(),set()去获取他们的默认值或者在线程内部改变他们的值。(说白了,ThreadLocal就是想在多线程下保证成员变量的安全)
20.多线程了解吗?答:可以从以下几个方面作出回答:
创建多线程的四种方式:
1.继承Thread类(缺点:Java只支持单继承)
2.实现Runnable接口(可返回执行结果,run()方法不可向外抛异常,只能内部消化)
3.实现Callable接口(不返回执行结果,call()方法允许向外抛出异常)
4.通过线程池创建线程,Executors工具类是用来创建线程池的,可以指定线程也可以不指定。
出现线程不安全的原因是什么?
答:如果我们创建多个线程,存在着共享数据,那么就有可能出现线程安全的问题:当其中一个线程操作共享数据时,还未操作完成,另外的线程就参与进来,导致共享数据的操作出现问题。
线程不安全解决办法?
要求一个线程操作共享数据时,只有当其完成操作共享数据,其他线程才会有机会执行共享数据。Java提供了两种方式来实现同步互斥访问:synchronized和lock。
多线程中wait()和sleep()的区别?
wait()会释放当前持有的锁,进行等待,sleep()不会释放锁;
wait()只能在同步代码块或同步方法内使用,sleep()可以在任意地方进行使用;
wait() notify()只唤醒一个线程 notifyAll()唤醒所有线程 不需要捕获异常,sleep()需要捕获异常;
推荐:由于sleep()不释放锁资源,容易导致死锁问题,而wait()不会,一般情况下推荐使用wait() 。
21.Java线程池的实现原理,主要方法ThreadPoolExecutor()答:线程池说白了就是一个线程集合workerSet和一个阻塞队列workQueue,当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中,workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue没有任务的时候,worker就会阻塞,直到队列中有任务了就取出来继续执行。
22.mysql索引用过吗?答:用过,用的最多的就是主键唯一索引。
什么是索引?
索引就像查词典一样,根据目录进行查找。
你都知道那些索引类型?
唯一索引(unique):不可出现相同的值,允许又null值;
普通索引(index):允许出现相同的索引内容;
主键索引(promary key):不允许出现相同的值;
全文索引(fulltext text):可以针对值中的某个单词,效率低;
组合索引(combination):将多个字段组到一个索引里,列值的组合必须唯一;
索引虽然好处好,但过多使用索引也会带来相反的问题
使用索引虽然可以提高查询效率,同时却会降低表的更新效率
建立索引会占用磁盘空间,索引建立过多,索引文件会膨胀很宽。
23.说一下你对Java动态代理的理解答:代理类在程序运行时创建的代理方式被称为动态代理。最直白的例子就是spring的面向切面编程AOP,我们能在一个切点之前执行一些操作,在一个切点后执行一些操作,这个切点就是一个个方法。这些方法所在的类肯定是被代理了,在代理过程中切入一些其他操作。
24.项目中是怎么处理事务的?答:Spring提供了好多事务管理机制,主要分为编程式事务和声明式事务两种。编程式事务:是指在代码中手动的管理事务的提交,回滚等操作,代码侵入型很强,如下实例:
try{ transactionManager.commit(status);}catch(Exception e) { transactionManager.rollback(status);thrownewInvoiceApplyException("异常失败");}复制代码
声明式事务:基于AOP面向切面,他将具体业务和事务处理部分解藕,代码侵入性很低,所以在实际项目开发中使用声明式事务较多。(声明式事务实现也分为两种,一是基于TX和AOP的xml配置文件方式,二是基于@Transactionl注解)如下实例:
//@Transactional 可以作用在接口、类、类方法。@Transactional(rollbackFor = Exception.class)复制代码
面试官这时又问:项目中使用注解的方式不会滚,能说下是什么情况吗?
答:1.检查你的方法是不是public;
2.你的异常类型是不是unchecked异常(Error或者RuntimeException(比如空指针,1/0))
unchecked异常:空指针等死检测不到的,叫unchecked异常。
checked异常:我们的编译器是能够检测到的,就叫checked异常;
3.数据库引擎要支持事务,如果是MySQL,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的;
4.是否开启了对注解的解析;
复制代码
5.spring是否扫描到你这个包,如下是扫描到org.test下面的包
复制代码
6.检查是不是同一个类中的方法调用(如a方法调用同一个类中的b方法)
7.异常是不是被你catch住了。
25.是否看过spring源码,能不能说一下ioc底层的实现原理答:以前我们要调用某个类中的方法都是要new对象,现在有了ioc我们把对象交给BeanFactory(bean工厂)来管理,用的时候直接去工厂中取。ioc是通过工厂模式,反射机制来实现的!
26.说说Jvm内存模型答:整个Jvm可以分为两大区线程共享区1.方法区(jdk1.8后方法区变为元空间):用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译的代码等数据2.堆:Java虚拟机所管理的内存中最大的一块区域,所有线程共享区域。此内存区域的唯一目的就是存放对象实例, Java堆是垃圾收集器管理的主要区域(GC堆从内存回收的角度讲,收集器基本上使用分代收集算法,所以Java堆还可以细分为:新生代和老年代,永久代(jdk1.8后改名为元空间))线程私有区(随线程生而生,随线程死而死)1.虚拟机栈:Java方法执行的内存模型,存储局部变量表,操作栈,动态链接,方法出口等信息;2.本地方法栈:本地方法被执行的时候会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息;3.程序计数器:程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。
27.对JVM的垃圾回收的认识?答:垃圾回收器的作用是回收(清除)和查找无用的对象。以便让JVM更有效的使用内存。
哪些东西需要回收?程序计算器、栈、本地方法栈3个区域的内存随着线程而生,随线程而灭;内存分配大体上在编译期间都已经确认;以此这些区域内存分配和回收都有确定性;故就不需要jvm打理回收了;方法结束或线程结束时,内存自然跟着回收了。而堆和方法区是动态分配的,只有在程序运行期间才知道哪些对象要建,内存分配和回收是动态的;故jvm只要关注此部分内存就好啦!!
什么时候回收?其实很简单-----就是东西没有人用了,就可以回收了!在jvm中,假设对象没有线程或方法使用则证明该对象可以回收了。如何判断对象没有被引用或使用呢?第一种算法--引用计数器算法(给对象添加一个引用计数器,当有引用指向它时计数器就+1,当引用失效时-1,计数器为0时就不可被引用了;此方法简单高效但有个缺点就是两个对象互相引用的时候;gc就没有办法回收此对象了;故很少采用此算法。)第二种方法--可达性分析算法(其算法思想就是通过gc_root节点作为起始点,往下搜索,搜索走过的路径叫做引用链;当一个对象没有一个gc root相连的话,则证明此对象已经没有使用,可以判断可以回收。)
用什么方式回收?答:1.标记-清除算法( 先标记好,然后统一回收;清除后产生零碎化内存;)2.复制算法(将可用内存划分为大小相等的两块,每次只使用一块,当这一块内存使用完后,就将还存活的对象复制到另外一块上;然后再把已经用过的内存一次清空;)3.分代收集算法(根据对象存活周期,分为新生代和老年代;针对不同的代采用不同的算法;)
28.JVM如何GC,新生代,老年代,持久代,都存储哪些东西?答:JVM的GC算法有:引用计数器算法,根搜索方法(详情可参考27)新生代:新生成的对象老年代:在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中(生命周期较长的对象)持久代:用于存放静态文件,如今Java类、方法等
29.什么情况下会发生栈内存溢出答:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。向有经验的同学请教,说内存使用量飙高,一般都是中间件引起的内存泄漏。因为我们线上服务使用 Java 语言开发,所以先从 JVM 垃圾收集器 GC 入手,可以比较直观地看出 JVM 内存状况。(jstat -gcutilpgrep -u mapp java1s)
30.讲讲你对Java反射机制的理解?答:首先我们要明白Java中创建对象的方式有四种1.使用new关键字:这是我们最常见的也是最简单的创建对象的方式2.使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去3.使用反序列化:当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象4.反射什么是反射?反射就是把Java类中的各个部分,映射成一个个的Java对象,拿到这些对象后可以做一些事情。(各个部分:成员变量,方法,构造方法,等信息)怎么得到反射的类?首先大家要明白一点,咱们写的代码是存储在后缀名是 .java的文件里的,但是它会被编译,最终真正去执行的是编译后的 .class文件;Java是面向对象的语言,一切皆对象,所以java认为 这些编译后的 class文件,这种事物也是一种对象,它也给抽象成了一种类,这个类就是Class。
31.mysql事务隔离级别?答:1.未提交读:所有事务都可以看到没有提交事务的数据;2.提交读:事务成功提交后才可以查询到;3.重复读:同一个事务多个实例读取数据时,可能将未提交的记录查询出来,而出现幻读(mysql默认级别);4.可串行化:强制的进行排序,在每个读数据行上添加共享锁。会导致大量超时现象和锁竞争;
32.RabbitMQ死信队列如何处理?答:不希望:(如果不做任何处理,当消费消息时出现异常,默认会不断的重试,这显然不是我们希望的)我们希望的:可以指定重试的次数,重试完了之后进入死信队列,然后就可以人为的对死信队列进行处理1.需要将一个Queue关联死信队列的Exchange和RoutingKey2.在UI页面可看到多次重试后的消息进入了死信队列3.处理死信队列---3.1 通过人工去处理死信队列---3.2 等待系统正常后把死信队列中的消息路由到Queue去处理
33.说下对Synchronized关键字的理解答:Synchronized是Java中解决并发问题的一种常见的方法,也是最简单一种方法(我们都知道synchronized可以让线程同步,所谓同步,就是同一时刻只有一个线程执行这段代码)。三个主要作用:(1)确保线程互斥的访问同步代码(2)保证共享变量的修改能够及时可见(3)有效解决重排序问题三种用法:(1)修饰普通方法(2)修饰静态方法(3)修饰代码块sychronized原理:
34.mybatis加载mappers有几种方式?
答:共4种
1.resource
2.url
3.class
4.package(优先级最高)
35.Mybatis底层原理?
一. mybatis是如何获取数据源的?
答:mybatis获取数据源的创建使用工厂模式,基本分为两种:有带连接池的数据源,不带连接池的数据源(类似jdbc)。
二. mybatis是如何获取SQL的?
三. mybatis是如何操作的?
四. mybatis有几种执行器?
五. mybatis一级缓存默认状态?怎么创建,怎么使用的?
后面还会持续更新
作者:余生一个帆
链接:https://juejin.cn/post/6909289701484527629
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。