2023年6月20日发(作者:)
100道中⾼级Java⾯试题整理JavaEE⾯试题整理⼀、Java基础篇1、JAVA中的⼏种基本数据类型是什么,各⾃占⽤多少字节?浮点类型:float(4字节)、double(8个字)整数类型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)字符类型:char(2字节)布尔类型:boolean(4字节)2、String类能被继承吗,为什么?不可以,因为String类有final修饰符,⽽final修饰的类是不能被继承的,实现细节不允许改变。3、 String,Stringbuffer,StringBuilder的区别?String:不可变字符串;StringBuffer:可变字符串、效率低、线程安全;StringBuilder:可变字符序列、效率⾼、线程不安全;String可以空赋值,后者不⾏,报错如果要操作少量的数据⽤ String;多线程操作字符串缓冲区下操作⼤量数据 StringBuffer;单线程操作字符串缓冲区下操作⼤量数据 StringBuilder(推荐使⽤)。4、java中==和equals和hashCode的区别==是运算符,⽤于⽐较两个变量是否相等。⼀般⽤于基本类型的⽐较equals,是Objec类的⽅法,⽤于⽐较两个对象是否相等,默认Object类的equals⽅法是⽐较两个对象的地址,跟==的结果⼀样。hashCode也是Object类的⼀个⽅法返回⼀个离散的int型整数。在集合类操作中使⽤,为了提⾼查询速度。(HashMap,HashSet等)5、int与integer的区别Integer是int的包装类,int则是java的⼀种基本数据类型Integer变量必须实例化后才能使⽤,⽽int变量不需要Integer实际是对象的引⽤,当new⼀个Integer时,实际上是⽣成⼀个指针指向此对象;⽽int则是直接存储数据值Integer的默认值是null,int的默认值是06、什么是内部类?内部类的作⽤含义:可以将⼀个类的定义放在另⼀个类的定义的内部,这就是内部类。内部类的作⽤:内部类可以很好的实现隐藏内部类拥有外围类的所有元素的访问权限可以实现多重继承(不要误解,这个是在⼀个外部类⾥⾯多个内部类继承不同基类达到⼀个外部类拥有多个基类的⽅法)可以避免接⼝中的⽅法和同⼀个类中的⽅法同名的问题7、抽象类和接⼝区别抽象类和接⼝都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象⽅法的⼦类对象,接⼝变量必须指向实现所有接⼝⽅法的类对象。抽象类要被⼦类继承,接⼝要被类实现。接⼝只能做⽅法申明,抽象类中可以做⽅法申明,也可以做⽅法实现接⼝⾥定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。抽象类⾥的抽象⽅法必须全部被⼦类所实现,如果⼦类不能全部实现⽗类抽象⽅法,那么该⼦类只能是抽象类。同样,⼀个实现接⼝的时候,如不能全部实现接⼝⽅法,那么该类也只能为抽象类。抽象⽅法只能申明,不能实现,接⼝是设计的结果 ,抽象类是重构的结果抽象类⾥可以没有抽象⽅法如果⼀个类⾥有抽象⽅法,那么这个类只能是抽象类抽象⽅法要被实现,所以不能是静态的,也不能是私有的。接⼝可继承接⼝,并可多继承接⼝,但类只能单根继承。8、进程和线程的区别进程是资源的分配和调度的⼀个独⽴单元,⽽线程是CPU调度的基本单元同⼀个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下⽂),⼀个进⾏⾄少包括⼀个线程。进程的创建调⽤fork或者vfork,⽽线程的创建调⽤pthread_create,进程结束后它拥有的所有线程都将销毁,⽽线程的结束不会影响同个进程中的其他线程的结束线程是轻两级的进程,它的创建和销毁所需要的时间⽐进程⼩很多,所有操作系统中的执⾏功能都是创建线程去完成的线程中执⾏时⼀般都要进⾏同步和互斥,因为他们共享同⼀进程的所有资源线程有⾃⼰的私有属性TCB,线程id,寄存器、硬件上下⽂,⽽进程也有⾃⼰的私有属性进程控制块PCB,这些私有属性是不被共享的,⽤来标⽰⼀个进程或⼀个线程的标志9、泛型通配符extends与super的区别 extends T> 只能⽤于⽅法返回,告诉编译器此返参的类型的最⼩继承边界为T,T和T的⽗类都能接收,但是⼊参类型⽆法确定,只能接受null的传⼊ super T>只能⽤于限定⽅法⼊参,告诉编译器⼊参只能是T或其⼦类型,⽽返参只能⽤Object类接收 既不能⽤于⼊参也不能⽤于返参10、error和exception有什么区别error 表⽰恢复不是不可能但很困难的情况下的⼀种严重问题。⽐如说内存溢出。不可能指望程序能处理这样的情况 exception 表⽰⼀种设计或实现问题。也就是说,它表⽰如果程序运⾏正常,从不会发⽣的情况。11、GC是什么? 为什么要有GCGC是垃圾收集的意思(Gabage Collection),内存处理是编程⼈员容易出现问题的地⽅,忘记或者错误的内存回收会导致程序或系统的不稳定甚⾄崩溃,Java提供的GC功能可以⾃动监测对象是否超过作⽤域从⽽达到⾃动回收内存的⽬的,Java语⾔没有提供释放已分配内存的显⽰操作⽅法。12、运⾏时异常与⼀般异常有何异同异常表⽰程序运⾏过程中可能出现的⾮正常状态,运⾏时异常表⽰虚拟机的通常操作中可能遇到的异常,是⼀种常见运⾏错误。java编译器要求⽅法必须声明抛出可能发⽣的⾮运⾏时异常,但是并不要求必须声明抛出未被捕获的运⾏时异常。13、描述⼀下JVM加载class⽂件的原理机制?JVM中类的装载是由ClassLoader和它的⼦类来实现的,Java ClassLoader 是⼀个重要的Java运⾏时系统组件。它负责在运⾏时查找和装⼊类⽂件的类。14、&和&&的区别&是位运算符,表⽰按位与运算,&&是逻辑运算符,表⽰逻辑与(and)15.什么是值传递和引⽤传递?对象被值传递,意味着传递了对象的⼀个副本。因此,就算是改变了对象副本,也不会影响源对象的值。对象被引⽤传递,意味着传递的并不是实际的对象,⽽是对象的引⽤。因此,外部对引⽤对象所做的改变会反映到所有的对象上。⼆、JVM篇1、JVM内存模型都有哪些程序计数器java虚拟机栈本地⽅法栈java堆⽅法区运⾏时常量池直接内存2、讲讲什么情况下会出现内存溢出,内存泄漏内存泄漏memory leak :是指程序在申请内存后,⽆法释放已申请的内存空间,⼀次内存泄漏似乎不会有⼤的影响,但内存泄漏堆积后的后果就是内存溢出。内存溢出 out of memory :指程序申请内存时,没有⾜够的内存供申请者使⽤,或者说,给了你⼀块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够⽤,此时就会报错OOM,即所谓的内存溢出。Java内存泄漏的根本原因是什么呢?长⽣命周期的对象持有短⽣命周期对象的引⽤就很可能发⽣内存泄漏,尽管短⽣命周期对象已经不再需要,但是因为长⽣命周期持有它的引⽤⽽导致不能被回收,这就是Java中内存泄漏的发⽣场景。3、说说Java线程栈Java线程栈从线程创建时存在,并且是私有的。线程栈⽤户存储栈帧,栈帧⽤于存储局部变量、中间运算结果。所以局部是不存在并发的问题,因为每个栈是私有的。虚拟机只会对Java栈进⾏⼆种操作:以栈帧为单位的压栈和出栈。对于执⾏引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与这个栈帧相关联的⽅法称为当前⽅法(Current Method)。执⾏引擎运⾏的所有字节码指令都只针对当前栈帧进⾏操作。4、类的实例化顺序⾸先是⽗类的静态变量和静态代码块(看两者的书写顺序);第⼆执⾏⼦类的静态变量和静态代码块(看两者的书写顺序);第三执⾏⽗类的成员变量赋值第四执⾏⽗类类的构造代码块第五执⾏⽗类的构造⽅法()执⾏⼦类的构造代码块第七执⾏⼦类的构造⽅法();总结,也就是说虽然客户端代码是new 的构造⽅法,但是构造⽅法确实是在整个实例创建中的最后⼀个调⽤。切记切记先是⽗类,再是⼦类;先是类静态变量和静态代码块,再是对象的成员变量和构造代码块–》构造⽅法。记住,构造⽅法最后调⽤成员变量优先构造代码块优先构造⽅法!!5、java类加载机制加载:通过类的全限定名获取类的⼆进制字节流,将字节流代表的静态存储结构转化为⽅法区的运⾏时数据结构。在内存⽣成这个类的class对象连接:包括三步验证,准备,解析验证:保证class⽂件的字节流中包含的信息符合当前虚拟机的要求,且不危害虚拟机⾃⾝安全准备:正式为类变量分配内存并设置类变量初始值解析:将常量池的符号引⽤替换为直接引⽤初始化:根据程序员的意愿初始化类变量6、⼀个对象的内存划分是怎样的?可分为3块区域:对象头,实例数据,对齐填充对象头由Mark world和类型指针组成mark World包括hash码,GC分代年龄,锁状态标志等。类型指针来确定这个对象是哪个类的实例实例数据是对象存储的真正的有效信息hostspot虚拟机要求对象的⼤⼩必须是8字节的整数倍7、内存泄漏和内存溢出的区别内存泄漏:分配出去的内存⽆法回收(可达却⽆⽤的对象⽆法被gc回收)内存溢出:程序要求的内存超出了系统能分配的范围(如栈满进栈,栈空出栈)8.垃圾收集算法有哪些标记-清除算法:⾸先标记出所有的对象,标记完成后统⼀回收(1效率问题:标记和清除两个过程效率都不⾼(2空间问题:产⽣碎⽚复制算法:将内存划分为⼀块较⼤的Eden空间(80%)和两块较⼩的Survivor空间(10%),每次使⽤Eden和其中的⼀块Survivor,当回收时,将两者中存活的对象⼀次性复制到另⼀块Survivor,并清空刚才⽤到的空间,如果这块Survivor不够,则启⽤分配担保机制,将多处的对象存储再⽼年代标记-整理算法:⾸先标记出所有的对象,回收时让存活的对象都向⼀端移动,直接清理端边界外的内存分代收集算法:将java堆分为新⽣代和⽼年代,垃圾回收时,新⽣代每次都有⼤量对象死去,所以采⽤复制算法,⽼年代存活的对象较多,使⽤标记-清除或标记-整理9、常见的垃圾收集器?Serial收集器:单线程收集器ParNew收集器:,新⽣代收集器,Serial收集器的多线程版本Parallel Scavenge收集器:新⽣代收集器,使⽤复制算法。是⽤来实现最⼤吞吐量(代码运⾏时间/(代码运⾏时间+垃圾收集的时间))Serial Old收集器:Serial收集器的⽼年代版本Parallel Old收集器:ParNew收集器的⽼年代版本(⼀般使⽤Parallel Scavenge + Parallel Old)CMS收集器:是⼀种以获取最短停顿时间为⽬标的收集器。分为4个步骤:初始标记,并发标记,重新标记,并发清除采⽤ 标记-清除算法(1)初始标记:标记GC Root能直接关联到的对象 (stop the world)(2)并发标记:进⾏Gc Root Tracing的过程(3)重新标记:修正并发标记期间⽤户线程序继续⼯作⽽导致的标记的变动(stop the world)(4)并发清除:清除未被标记的对象G1收集器:可以独⽴的管理整个gc堆。步骤:初始标记,并发标记,最终标记,筛选回收(⾸先对各个Region价值排序)从整体上看是:标记-整理算法 , 从局部上看(两个region)采⽤复制算法10、什么情况下对象进⼊⽼年代⼤对象直接进⼊⽼年代(需要⼤量连续空间的对象)。常见的⼤对象就是很长的字符串和数组长期存活的对象进⼊⽼年代。每个对象有⼀个年龄计数器。每熬过⼀次moinor gc,年龄就增加⼀岁。当年龄增加到⼀定程度(默认为15)就会晋升到⽼年代(通过MaxTenuringThreshold设置)。动态年龄判断:如果survivor空间某个年龄对象的⼤⼩⼤于survivor空间的⼀半,年龄⼤于或等于的直接进⼊⽼年代空间分配担保:复制算法中,survivor中⽆法容纳的对象将通过分配担保机制直接进⼊⽼年代11、什么时候进⾏GC程序员不能控制具体的时间Eden区满了会触发minor GC,⽼年代满或调⽤执⾏Full GC三、Tomcat篇1、Tomcat 有哪⼏种Connector 运⾏模式(优化)?bio:传统的Java I/O操作,同步且阻塞IO。nio:JDK1.4开始⽀持,同步阻塞或同步⾮阻塞IO。aio(nio.2):JDK7开始⽀持,异步⾮阻塞IO。apr:Tomcat将以JNI的形式调⽤Apache HTTP服务器的核⼼动态链接库来处理⽂件读取或⽹络传输操作,从⽽⼤⼤地 提⾼Tomcat对静态⽂件的处理性能。2、Tomcat容器是如何创建servlet类实例?⽤到了什么原理?当容器启动时,会读取在webapps⽬录下所有的web应⽤中的⽂件,然后对xml⽂件进⾏解析,并读取servlet注册信息。然后,将每个应⽤中注册的servlet类都进⾏加载,并通过反射的⽅式实例化。(有时候也是在第⼀次请求时实例化)在servlet注册时加上如果为正数,则在⼀开始就实例化,如果不写或为负数,则第⼀次请求实例化。3、Tomcat内存调优内存⽅式的设置是在中,调整⼀下JAVA_OPTS变量即可,因为后⾯的启动参数会把JAVA_OPTS作为JVM的启动参数来处理。具体设置如下:JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4"
其各项参数如下:-Xmx3550m:设置JVM最⼤可⽤内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代⼤⼩为2G。整个堆⼤⼩=年轻代⼤⼩ + 年⽼代⼤⼩ + 持久代⼤⼩。持久代⼀般固定⼤⼩为64m,所以增⼤年轻代后,将会减⼩年⽼代⼤⼩。此值对系统性能影响较⼤,Sun官⽅推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈⼤⼩。JDK5.0以后每个线程堆栈⼤⼩为1M,以前每个线程堆栈⼤⼩为256K。更具应⽤的线程所需内存⼤⼩进⾏调整。在相同物理内存下,减⼩这个值能⽣成更多的线程。但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成,经验值在3000~5000左右。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年⽼代的⽐值(除去持久代)。设置为4,则年轻代与年⽼代所占⽐值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的⼤⼩⽐值。设置为4,则两个Survivor区与⼀个Eden区的⽐值为2:4,⼀个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代⼤⼩为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最⼤年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进⼊年⽼代。对于年⽼代⽐4、垃圾回收策略调优垃圾回收的设置也是在中,调整JAVA_OPTS变量。具体设置如下:JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100" 具体的垃圾回收策略及相应策略的各项参数如下:串⾏收集器(JDK1.5以前主要的回收⽅式)-XX:+UseSerialGC:设置串⾏收集器并⾏收集器(吞吐量优先)⽰例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:+UseParallelGC:选择垃圾收集器为并⾏收集器。此配置仅对年轻代有效。即上述配置下,年轻代使⽤并发收集,⽽年⽼代仍旧使⽤串⾏收集。
-XX:ParallelGCThreads=20:配置并⾏收集器的线程数,即:同时多少个线程⼀起进⾏垃圾回收。此值最好配置与处理器数⽬相等。
-XX:+UseParallelOldGC:配置年⽼代垃圾收集⽅式为并⾏收集。JDK6.0⽀持对年⽼代并⾏收集
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果⽆法满⾜此时间,JVM会⾃动调整年轻代⼤⼩,以满⾜此值。
-XX:+UseAdaptiveSizePolicy:设置此选项后,并⾏收集器会⾃动选择年轻代区⼤⼩和相应的Survivor区⽐例,以达到⽬标系统规定的最低相应时间或者收集频率等,此值建议使⽤并⾏收集器时,⼀直打开。
并发收集器(响应时间优先)
⽰例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC:设置年⽼代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代⼤⼩最好⽤-Xmn设置。
-XX:+UseParNewGC: 设置年轻代为并⾏收集。可与CMS收集同时使⽤。JDK5.0以上,JVM会根据系统配置⾃⾏设置,所以⽆需再设置此值。
-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进⾏压缩、整理,所以运⾏⼀段时间以后会产⽣“碎⽚”,使得运⾏效率降低。此值设置运⾏多少次GC以后对内存空间进⾏压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年⽼代的压缩。可能会影响性能,但是可以消除碎⽚
5、添加JMS远程监控对于部署在局域⽹内其它机器上的Tomcat,可以打开JMX监控端⼝,局域⽹其它机器就可以通过这个端⼝查看⼀些常⽤的参数(但⼀些⽐较复杂的功能不⽀持),同样是在JVM启动参数中配置即可,配置如下:-=false -ticate=false
-me=192.168.71.38 设置JVM的JMS监控监听的IP地址,主要是为了防⽌错误的监听成127.0.0.1这个内⽹地址
-=1090 设置JVM的JMS监控的端⼝
-=false 设置JVM的JMS监控不实⽤SSL
-ticate=false 设置JVM的JMS监控不需要认证6、请解释Tomcat中使⽤的连接器是什么?在Tomcat中,使⽤了两种类型的连接器:HTTP连接器:它有许多可以更改的属性,以确定它的⼯作⽅式和访问功能,如重定向和代理转发AJP连接器:它以与HTTP连接器相同的⽅式⼯作,但是他们使⽤的是HTTP的AJP协议。AJP连接器通常通过插件技术mod_jk在Tomcat中实现7、解释什么是Tomcat Valve?Tomcat Valve——Tomcat 4引⼊的新技术,它允许您将Java类的实例链接到⼀个特定的Catalina容器。8、说明Tomcat配置了多少个Valve?Tomcat配置了四种类型的Valve:访问⽇志远程地址过滤远程主机过滤器客户请求记录器9、请说明NAT协议的⽬的是什么?NAT协议的⽬的是将私有IP地址从公共IP地址隐藏起来,并给组织提供⼀定的安全性。四、MyBatis篇1、Mybaits的优点:基于SQL语句编程,相当灵活,不会对应⽤程序或者数据库的现有设计造成任何影响,SQL写在XML⾥,解除sql与程序代码的耦合,便于统⼀管理;提供XML标签,⽀持编写动态SQL语句,并可重⽤。与JDBC相⽐,减少了50%以上的代码量,消除了JDBC⼤量冗余的代码,不需要⼿动开关连接;很好的与各种数据库兼容(因为MyBatis使⽤JDBC来连接数据库,所以只要JDBC⽀持的数据库MyBatis都⽀持)。能够与Spring很好的集成;提供映射标签,⽀持对象与数据库的ORM字段关系映射;提供对象关系映射标签,⽀持对象关系组件维护。2、MyBatis框架的缺点:SQL语句的编写⼯作量较⼤,尤其当字段多、关联表多时,对开发⼈员编写SQL语句的功底有⼀定要求。SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。3、MyBatis与Hibernate有哪些不同?Mybatis和hibernate不同,它不完全是⼀个ORM框架,因为MyBatis需要程序员⾃⼰编写Sql语句。Mybatis直接编写原⽣态sql,可以严格控制sql执⾏性能,灵活度⾼,⾮常适合对关系数据模型要求不⾼的软件开发,因为这类软件需求变化频繁,⼀但需求变化要求迅速输出成果。但是灵活的前提是mybatis⽆法做到数据库⽆关性,如果需要实现⽀持多种数据库的软件,则需要⾃定义多套sql映射⽂件,⼯作量⼤。Hibernate对象/关系映射能⼒强,数据库⽆关性好,对于关系模型要求⾼的软件,如果⽤hibernate开发可以节省很多代码,提⾼效率。4、#{}和${}的区别是什么#{}是预编译处理,${}是字符串替换。Mybatis在处理#{}时,会将sql中的#{}替换为?号,调⽤PreparedStatement的set⽅法来赋值;Mybatis在处理${}时,就是把${}替换成变量的值。使⽤#{}可以有效的防⽌SQL注⼊,提⾼系统安全性。5、Mybatis是如何进⾏分页的?分页插件的原理是什么?Mybatis使⽤RowBounds对象进⾏分页,它是针对ResultSet结果集执⾏的内存分页,⽽⾮物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使⽤分页插件来完成物理分页。分页插件的基本原理是使⽤Mybatis提供的插件接⼝,实现⾃定义插件,在插件的拦截⽅法内拦截待执⾏的sql,然后重写sql,根据dialect⽅⾔,添加对应的物理分页语句和物理分页参数。6、Xml映射⽂件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?、、、、,加上动态sql的9个标签,其中为sql⽚段标签,通过标签引⼊sql⽚段,为不⽀持⾃增的主键⽣成策略标签。7、最佳实践中,通常⼀个Xml映射⽂件,都会写⼀个Dao接⼝与之对应,请问,这个Dao接⼝的⼯作原理是什么?Dao接⼝⾥的⽅法,参数不同时,⽅法能重载吗?Dao接⼝,就是⼈们常说的Mapper接⼝,接⼝的全限名,就是映射⽂件中的namespace的值,接⼝的⽅法名,就是映射⽂件中MappedStatement的id值,接⼝⽅法内的参数,就是传递给sql的参数。Mapper接⼝是没有实现类的,当调⽤接⼝⽅法时,接⼝全限名+⽅法名拼接字符串作为key值,可唯⼀定位⼀个MappedStatement,举例:udentById,可以唯⼀找到namespace为tDao下⾯id = findStudentById的MappedStatement。在Mybatis中,每⼀个、、、标签,都会被解析为⼀个MappedStatement对象。Dao接⼝⾥的⽅法,是不能重载的,因为是全限名+⽅法名的保存和寻找策略。Dao接⼝的⼯作原理是JDK动态代理,Mybatis运⾏时会使⽤JDK动态代理为Dao接⼝⽣成代理proxy对象,代理对象proxy会拦截接⼝⽅法,转⽽执⾏MappedStatement所代表的sql,然后将sql执⾏结果返回。8、Mybatis动态sql是做什么的?都有哪些动态sql?能简述⼀下动态sql的执⾏原理不?Mybatis动态sql可以让我们在Xml映射⽂件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。其执⾏原理为,使⽤OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。9、Mybatis是如何将sql执⾏结果封装为⽬标对象并返回的?都有哪些映射形式?第⼀种是使⽤标签,逐⼀定义列名和对象属性名之间的映射关系。第⼆种是使⽤sql列的别名功能,将列别名书写为对象属性名,⽐如T_NAME AS NAME,对象属性名⼀般是name,⼩写,但是列名不区分⼤⼩写,Mybatis会忽略列名⼤⼩写,智能找到与之对应对象属性名,你甚⾄可以写成T_NAME AS NaMe,Mybatis⼀样可以正常⼯作。有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使⽤反射给对象的属性逐⼀赋值并返回,那些找不到映射关系的属性,是⽆法完成赋值的。10、Mybatis是否⽀持延迟加载?如果⽀持,它的实现原理是什么?Mybatis仅⽀持association关联对象和collection关联集合对象的延迟加载,association指的就是⼀对⼀,collection指的就是⼀对多查询。在Mybatis配置⽂件中,可以配置是否启⽤延迟加载lazyLoadingEnabled=true|false。它的原理是,使⽤CGLIB创建⽬标对象的代理对象,当调⽤⽬标⽅法时,进⼊拦截器⽅法,⽐如调⽤().getName(),拦截器invoke()⽅法发现()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调⽤(b),于是a的对象b属性就有值了,接着完成().getName()⽅法的调⽤。这就是延迟加载的基本原理。当然了,不光是Mybatis,⼏乎所有的包括Hibernate,⽀持延迟加载的原理都是⼀样的。11、Mybatis的Xml映射⽂件中,不同的Xml映射⽂件,id是否可以重复?不同的Xml映射⽂件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践⽽已。原因就是namespace+id是作为Map
@Before 注解使⽤这个Advice。返回之后通知(After Retuning Advice): 在连接点正常结束之后执⾏的Advice。例如,如果⼀个⽅法没有抛出异常正常返回。通过@AfterReturning 关注使⽤它。抛出(异常)后执⾏通知(After Throwing Advice): 如果⼀个⽅法通过抛出异常来退出的话,这个Advice就会被执⾏。通⽤@AfterThrowing 注解来使⽤。后置通知(After Advice): ⽆论连接点是通过什么⽅式退出的(正常返回或者抛出异常)都会执⾏在结束后执⾏这些Advice。通过
@After注解使⽤。围绕通知(Around Advice): 围绕连接点执⾏的Advice,就你⼀个⽅法调⽤。这是最强⼤的Advice。通过
@Around注解使⽤。9、 什么是Spring的依赖注⼊依赖注⼊,是IOC的⼀个⽅⾯,是个通常的概念,它有多种解释。这概念是说你不⽤创建对象,⽽只需要描述它如何被创建。你不在代码⾥直接组装你的组件和服务,但是要在配置⽂件⾥描述哪些组件需要哪些服务,之后⼀个容器(IOC容器)负责把他们组装起来。10、有哪些不同类型的IOC(依赖注⼊)⽅式?构造器依赖注⼊:构造器依赖注⼊通过容器触发⼀个类的构造器来实现的,该类有⼀系列参数,每个参数代表⼀个对其他类的依赖。Setter⽅法注⼊:Setter⽅法注⼊是容器通过调⽤⽆参构造器或⽆参static⼯⼚ ⽅法实例化bean之后,调⽤该bean的setter⽅法,即实现了基于setter的依赖注⼊。11、哪种依赖注⼊⽅式你建议使⽤,构造器注⼊,还是 Setter⽅法注⼊?两种依赖⽅式都可以使⽤,构造器注⼊和Setter⽅法注⼊。最好的解决⽅案是⽤构造器参数实现强制依赖,setter⽅法实现可选依赖。12、 如何给Spring 容器提供配置元数据?这⾥有三种重要的⽅法给Spring 容器提供配置元数据。XML配置⽂件。基于注解的配置。基于java的配置。六、SpringMVC⾯试题整理七、Redis篇1、什么是Redis?简述它的优缺点?Redis本质上是⼀个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进⾏操作,定期通过异步操作把数据库数据flush到硬盘上进⾏保存。因为是纯内存操作,Redis的性能⾮常出⾊,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的出⾊之处不仅仅是性能,Redis最⼤的魅⼒是⽀持保存多种数据结构,此外单个value的最⼤限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以⽤来实现很多有⽤的功能。⽐⽅说⽤他的List来做FIFO双向链表,实现⼀个轻量级的⾼性 能消息队列服务,⽤他的Set可以做⾼性能的tag系统等等。另外Redis也可以对存⼊的Key-Value设置expire时间,因此也可以被当作⼀ 个功能加强版的memcached来⽤。 Redis的主要缺点是数据库容量受到物理内存的限制,不能⽤作海量数据的⾼性能读写,因此Redis适合的场景主要局限在较⼩数据量的⾼性能操作和运算上。2、Redis⽀持哪⼏种数据类型?String、List、Set、Sorted Set、hashes3、Redis有哪⼏种数据淘汰策略?noeviction:返回错误当内存限制达到并且客户端尝试执⾏会让更多内存被使⽤的命令(⼤部分的写⼊指令,但DEL和⼏个例外)allkeys-lru: 尝试回收最少使⽤的键(LRU),使得新添加的数据有空间存放。volatile-lru: 尝试回收最少使⽤的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。allkeys-random: 回收随机的键使得新添加的数据有空间存放。vlatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。4、⼀个字符串类型的值能存储最⼤容量是多少?512M5、为什么Redis需要把所有数据放到内存中?Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的⽅式将数据写⼊磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。 如果设置了最⼤使⽤的内存,则数据已有记录数达到内存限值后不能继续插⼊新值。6、Redis集群最⼤节点个数是多少?16384个。7、Redis有哪些适合的场景?会话缓存(Session Cache)最常⽤的⼀种使⽤Redis的情景是会话缓存(session cache)。⽤Redis缓存会话⽐其他存储(如Memcached)的优势在于:Redis提供持久化。当维护⼀个不是严格要求⼀致性的缓存时,如果⽤户的购物车信息全部丢失,⼤部分⼈都会不⾼兴的,现在,他们还会这样吗?幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使⽤Redis来缓存会话的⽂档。甚⾄⼴为⼈知的商业平台Magento也提供Redis的插件。全页缓存(FPC)除基本的会话token之外,Redis还提供很简便的FPC平台。回到⼀致性问题,即使重启了Redis实例,因为有磁盘的持久化,⽤户也不会看到页⾯加载速度的下降,这是⼀个极⼤改进,类似PHP本地FPC。再次以Magento为例,Magento提供⼀个插件来使⽤Redis作为全页缓存后端。此外,对WordPress的⽤户来说,Pantheon有⼀个⾮常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页⾯。队列Reids在内存存储引擎领域的⼀⼤优点是提供 list 和 set 操作,这使得Redis能作为⼀个很好的消息队列平台来使⽤。Redis作为队列使⽤的操作,就类似于本地程序语⾔(如Python)对 list 的 push/pop 操作。如果你快速的在Google中搜索“Redis queues”,你马上就能找到⼤量的开源项⽬,这些项⽬的⽬的就是利⽤Redis创建⾮常好的后端⼯具,以满⾜各种队列需求。例如,Celery有⼀个后台就是使⽤Redis作为broker,你可以从这⾥去查看。排⾏榜/计数器Redis在内存中对数字进⾏递增或递减的操作实现的⾮常好。集合(Set)和有序集合(Sorted Set)也使得我们在执⾏这些操作的时候变的⾮常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个⽤户–我们称之为“user_scores”,我们只需要像下⾯⼀样执⾏即可:当然,这是假定你是根据你⽤户的分数做递增的排序。如果你想返回⽤户及⽤户的分数,你需要这样执⾏:ZRANGE user_scores 0 10 WITHSCORESAgora Games就是⼀个很好的例⼦,⽤Ruby实现的,它的排⾏榜就是使⽤Redis来存储数据的,你可以在这⾥看到。发布/订阅最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使⽤场景确实⾮常多。我已看见⼈们在社交⽹络连接中使⽤,还可作为基于发布/订阅的脚本触发器,甚⾄⽤Redis的发布/订阅功能来建⽴聊天系统!10、Redis集群⽅案应该怎么做?都有哪些⽅案?twemproxy,⼤概概念是,它类似于⼀个代理⽅式,使⽤⽅法和普通redis⽆任何区别,设置好它下属的多个redis实例后,使⽤时在本需要连接redis的地⽅改为连接twemproxy,它会以⼀个代理的⾝份接收请求并使⽤⼀致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使⽤⽅式简便(相对redis只需修改连接端⼝),对旧项⽬扩展的⾸选。 问题:twemproxy⾃⾝单端⼝实例的压⼒,使⽤⼀致性hash后,对redis节点数量改变时候的计算值的改变,数据⽆法⾃动移动到新的节点。codis,⽬前⽤的最多的集群⽅案,基本和twemproxy⼀致的效果,但它⽀持在 节点数量改变情况下,旧节点数据可恢复到新hash节点。redis cluster3.0⾃带的集群,特点在于他的分布式算法不是⼀致性hash,⽽是hash槽的概念,以及⾃⾝⽀持节点设置从节点。具体看官⽅⽂档介绍。在业务代码层实现,起⼏个毫⽆关联的redis实例,在代码层,对key 进⾏hash计算,然后去对应的redis实例操作数据。 这种⽅式对hash层代码要求⽐较⾼,考虑部分包括,节点失效后的替代算法⽅案,数据震荡后的⾃动脚本恢复,实例的监控,等等。11、Redis⽀持的Java客户端都有哪些?官⽅推荐⽤哪个?Redisson、Jedis、lettuce等等,官⽅推荐使⽤Redisson。12、Jedis与Redisson对⽐有什么优缺点?Jedis是Redis的Java实现的客户端,其API提供了⽐较全⾯的Redis命令的⽀持;Redisson实现了分布式和可扩展的Java数据结构,和Jedis相⽐,功能较为简单,不⽀持字符串操作,不⽀持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使⽤者对Redis的关注分离,从⽽让使⽤者能够将精⼒更集中地放在处理业务逻辑上。13、说说Redis哈希槽的概念?Redis集群没有使⽤⼀致性hash,⽽是引⼊了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责⼀部分hash槽。14、Redis集群的主从复制模型是怎样的?为了使在部分节点失败或者⼤部分节点⽆法通信的情况下集群仍然可⽤,所以集群使⽤了主从复制模型,每个节点都会有N-1个复制品.15、Redis集群会有写操作丢失吗?为什么?Redis并不能保证数据的强⼀致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。16、Redis中的管道有什么⽤?⼀次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,⽽不⽤等待回复,最后在⼀个步骤中读取该答复。这就是管道(pipelining),是⼀种⼏⼗年来⼴泛使⽤的技术。例如许多POP3协议已经实现⽀持这个功能,⼤⼤加快了从服务器下载新邮件的过程。17、怎么理解Redis事务?事务是⼀个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执⾏。事务在执⾏的过程中,不会被其他客户端发送来的命令请求所打断。事务是⼀个原⼦操作:事务中的命令要么全部被执⾏,要么全部都不执⾏。18、Redis事务相关的命令有哪⼏个?MULTI、EXEC、DISCARD、WATCH19、Redis如何做内存优化?尽可能使⽤散列表(hashes),散列表(是说散列表⾥⾯存储的数少)使⽤的内存⾮常⼩,所以你应该尽可能的将你的数据模型抽象到⼀个散列表⾥⾯。⽐如你的web系统中有⼀个⽤户对象,不要为这个⽤户的名称,姓⽒,邮箱,密码设置单独的key,⽽是应该把这个⽤户的所有信息存储到⼀张散列表⾥⾯.⼋、Mongodb篇1、使⽤mongodb的优点⾯向⽂件⾼性能⾼可⽤易扩展可分⽚对数据存储友好2、MongoDB⽀持存储过程吗?如果⽀持的话,怎么⽤?MongoDB⽀持存储过程,它是javascript写的,保存在表中。3、MySQL和MongoDB之间最基本的区别是什么?关系型数据库与⾮关系型数据库的区别,即数据存储结构的不同。4、如何理解MongoDB中的GridFS机制,MongoDB为何使⽤GridFS来存储⽂件?GridFS是⼀种将⼤型⽂件存储在MongoDB中的⽂件规范。使⽤GridFS可以将⼤⽂件分隔成多个⼩⽂档存放,这样我们能够有效的保存⼤⽂档,⽽且解决了BSON对象有限制的问题。5、如果⼀个分⽚(Shard)停⽌或很慢的时候,发起⼀个查询会怎样?如果⼀个分⽚停⽌了,除⾮查询设置了“Partial”选项,,否则查询会返回⼀个错误。如果⼀个分⽚响应很慢,MongoDB会等待它的响应。6、 Mongodb 的索引注意事项?索引很有⽤,但是它也是有成本的——它占内存,让写⼊变慢;mongoDB通常在⼀次查询⾥使⽤⼀个索引,所以多个字段的查询或者排序需要复合索引才能更加⾼效;复合索引的顺序⾮常重要在⽣成环境构建索引往往开销很⼤,时间也不可以接受,在数据量庞⼤之前尽量进⾏查询优化和构建索引;避免昂贵的查询,使⽤查询分析器记录那些开销很⼤的查询便于问题排查;通过减少扫描⽂档数量来优化查询,使⽤explai对开销⼤的查询进⾏分析并优化;索引是⽤来查询⼩范围数据的,不适合使⽤索引的情况:
2023年6月20日发(作者:)
100道中⾼级Java⾯试题整理JavaEE⾯试题整理⼀、Java基础篇1、JAVA中的⼏种基本数据类型是什么,各⾃占⽤多少字节?浮点类型:float(4字节)、double(8个字)整数类型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)字符类型:char(2字节)布尔类型:boolean(4字节)2、String类能被继承吗,为什么?不可以,因为String类有final修饰符,⽽final修饰的类是不能被继承的,实现细节不允许改变。3、 String,Stringbuffer,StringBuilder的区别?String:不可变字符串;StringBuffer:可变字符串、效率低、线程安全;StringBuilder:可变字符序列、效率⾼、线程不安全;String可以空赋值,后者不⾏,报错如果要操作少量的数据⽤ String;多线程操作字符串缓冲区下操作⼤量数据 StringBuffer;单线程操作字符串缓冲区下操作⼤量数据 StringBuilder(推荐使⽤)。4、java中==和equals和hashCode的区别==是运算符,⽤于⽐较两个变量是否相等。⼀般⽤于基本类型的⽐较equals,是Objec类的⽅法,⽤于⽐较两个对象是否相等,默认Object类的equals⽅法是⽐较两个对象的地址,跟==的结果⼀样。hashCode也是Object类的⼀个⽅法返回⼀个离散的int型整数。在集合类操作中使⽤,为了提⾼查询速度。(HashMap,HashSet等)5、int与integer的区别Integer是int的包装类,int则是java的⼀种基本数据类型Integer变量必须实例化后才能使⽤,⽽int变量不需要Integer实际是对象的引⽤,当new⼀个Integer时,实际上是⽣成⼀个指针指向此对象;⽽int则是直接存储数据值Integer的默认值是null,int的默认值是06、什么是内部类?内部类的作⽤含义:可以将⼀个类的定义放在另⼀个类的定义的内部,这就是内部类。内部类的作⽤:内部类可以很好的实现隐藏内部类拥有外围类的所有元素的访问权限可以实现多重继承(不要误解,这个是在⼀个外部类⾥⾯多个内部类继承不同基类达到⼀个外部类拥有多个基类的⽅法)可以避免接⼝中的⽅法和同⼀个类中的⽅法同名的问题7、抽象类和接⼝区别抽象类和接⼝都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象⽅法的⼦类对象,接⼝变量必须指向实现所有接⼝⽅法的类对象。抽象类要被⼦类继承,接⼝要被类实现。接⼝只能做⽅法申明,抽象类中可以做⽅法申明,也可以做⽅法实现接⼝⾥定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。抽象类⾥的抽象⽅法必须全部被⼦类所实现,如果⼦类不能全部实现⽗类抽象⽅法,那么该⼦类只能是抽象类。同样,⼀个实现接⼝的时候,如不能全部实现接⼝⽅法,那么该类也只能为抽象类。抽象⽅法只能申明,不能实现,接⼝是设计的结果 ,抽象类是重构的结果抽象类⾥可以没有抽象⽅法如果⼀个类⾥有抽象⽅法,那么这个类只能是抽象类抽象⽅法要被实现,所以不能是静态的,也不能是私有的。接⼝可继承接⼝,并可多继承接⼝,但类只能单根继承。8、进程和线程的区别进程是资源的分配和调度的⼀个独⽴单元,⽽线程是CPU调度的基本单元同⼀个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下⽂),⼀个进⾏⾄少包括⼀个线程。进程的创建调⽤fork或者vfork,⽽线程的创建调⽤pthread_create,进程结束后它拥有的所有线程都将销毁,⽽线程的结束不会影响同个进程中的其他线程的结束线程是轻两级的进程,它的创建和销毁所需要的时间⽐进程⼩很多,所有操作系统中的执⾏功能都是创建线程去完成的线程中执⾏时⼀般都要进⾏同步和互斥,因为他们共享同⼀进程的所有资源线程有⾃⼰的私有属性TCB,线程id,寄存器、硬件上下⽂,⽽进程也有⾃⼰的私有属性进程控制块PCB,这些私有属性是不被共享的,⽤来标⽰⼀个进程或⼀个线程的标志9、泛型通配符extends与super的区别 extends T> 只能⽤于⽅法返回,告诉编译器此返参的类型的最⼩继承边界为T,T和T的⽗类都能接收,但是⼊参类型⽆法确定,只能接受null的传⼊ super T>只能⽤于限定⽅法⼊参,告诉编译器⼊参只能是T或其⼦类型,⽽返参只能⽤Object类接收 既不能⽤于⼊参也不能⽤于返参10、error和exception有什么区别error 表⽰恢复不是不可能但很困难的情况下的⼀种严重问题。⽐如说内存溢出。不可能指望程序能处理这样的情况 exception 表⽰⼀种设计或实现问题。也就是说,它表⽰如果程序运⾏正常,从不会发⽣的情况。11、GC是什么? 为什么要有GCGC是垃圾收集的意思(Gabage Collection),内存处理是编程⼈员容易出现问题的地⽅,忘记或者错误的内存回收会导致程序或系统的不稳定甚⾄崩溃,Java提供的GC功能可以⾃动监测对象是否超过作⽤域从⽽达到⾃动回收内存的⽬的,Java语⾔没有提供释放已分配内存的显⽰操作⽅法。12、运⾏时异常与⼀般异常有何异同异常表⽰程序运⾏过程中可能出现的⾮正常状态,运⾏时异常表⽰虚拟机的通常操作中可能遇到的异常,是⼀种常见运⾏错误。java编译器要求⽅法必须声明抛出可能发⽣的⾮运⾏时异常,但是并不要求必须声明抛出未被捕获的运⾏时异常。13、描述⼀下JVM加载class⽂件的原理机制?JVM中类的装载是由ClassLoader和它的⼦类来实现的,Java ClassLoader 是⼀个重要的Java运⾏时系统组件。它负责在运⾏时查找和装⼊类⽂件的类。14、&和&&的区别&是位运算符,表⽰按位与运算,&&是逻辑运算符,表⽰逻辑与(and)15.什么是值传递和引⽤传递?对象被值传递,意味着传递了对象的⼀个副本。因此,就算是改变了对象副本,也不会影响源对象的值。对象被引⽤传递,意味着传递的并不是实际的对象,⽽是对象的引⽤。因此,外部对引⽤对象所做的改变会反映到所有的对象上。⼆、JVM篇1、JVM内存模型都有哪些程序计数器java虚拟机栈本地⽅法栈java堆⽅法区运⾏时常量池直接内存2、讲讲什么情况下会出现内存溢出,内存泄漏内存泄漏memory leak :是指程序在申请内存后,⽆法释放已申请的内存空间,⼀次内存泄漏似乎不会有⼤的影响,但内存泄漏堆积后的后果就是内存溢出。内存溢出 out of memory :指程序申请内存时,没有⾜够的内存供申请者使⽤,或者说,给了你⼀块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够⽤,此时就会报错OOM,即所谓的内存溢出。Java内存泄漏的根本原因是什么呢?长⽣命周期的对象持有短⽣命周期对象的引⽤就很可能发⽣内存泄漏,尽管短⽣命周期对象已经不再需要,但是因为长⽣命周期持有它的引⽤⽽导致不能被回收,这就是Java中内存泄漏的发⽣场景。3、说说Java线程栈Java线程栈从线程创建时存在,并且是私有的。线程栈⽤户存储栈帧,栈帧⽤于存储局部变量、中间运算结果。所以局部是不存在并发的问题,因为每个栈是私有的。虚拟机只会对Java栈进⾏⼆种操作:以栈帧为单位的压栈和出栈。对于执⾏引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与这个栈帧相关联的⽅法称为当前⽅法(Current Method)。执⾏引擎运⾏的所有字节码指令都只针对当前栈帧进⾏操作。4、类的实例化顺序⾸先是⽗类的静态变量和静态代码块(看两者的书写顺序);第⼆执⾏⼦类的静态变量和静态代码块(看两者的书写顺序);第三执⾏⽗类的成员变量赋值第四执⾏⽗类类的构造代码块第五执⾏⽗类的构造⽅法()执⾏⼦类的构造代码块第七执⾏⼦类的构造⽅法();总结,也就是说虽然客户端代码是new 的构造⽅法,但是构造⽅法确实是在整个实例创建中的最后⼀个调⽤。切记切记先是⽗类,再是⼦类;先是类静态变量和静态代码块,再是对象的成员变量和构造代码块–》构造⽅法。记住,构造⽅法最后调⽤成员变量优先构造代码块优先构造⽅法!!5、java类加载机制加载:通过类的全限定名获取类的⼆进制字节流,将字节流代表的静态存储结构转化为⽅法区的运⾏时数据结构。在内存⽣成这个类的class对象连接:包括三步验证,准备,解析验证:保证class⽂件的字节流中包含的信息符合当前虚拟机的要求,且不危害虚拟机⾃⾝安全准备:正式为类变量分配内存并设置类变量初始值解析:将常量池的符号引⽤替换为直接引⽤初始化:根据程序员的意愿初始化类变量6、⼀个对象的内存划分是怎样的?可分为3块区域:对象头,实例数据,对齐填充对象头由Mark world和类型指针组成mark World包括hash码,GC分代年龄,锁状态标志等。类型指针来确定这个对象是哪个类的实例实例数据是对象存储的真正的有效信息hostspot虚拟机要求对象的⼤⼩必须是8字节的整数倍7、内存泄漏和内存溢出的区别内存泄漏:分配出去的内存⽆法回收(可达却⽆⽤的对象⽆法被gc回收)内存溢出:程序要求的内存超出了系统能分配的范围(如栈满进栈,栈空出栈)8.垃圾收集算法有哪些标记-清除算法:⾸先标记出所有的对象,标记完成后统⼀回收(1效率问题:标记和清除两个过程效率都不⾼(2空间问题:产⽣碎⽚复制算法:将内存划分为⼀块较⼤的Eden空间(80%)和两块较⼩的Survivor空间(10%),每次使⽤Eden和其中的⼀块Survivor,当回收时,将两者中存活的对象⼀次性复制到另⼀块Survivor,并清空刚才⽤到的空间,如果这块Survivor不够,则启⽤分配担保机制,将多处的对象存储再⽼年代标记-整理算法:⾸先标记出所有的对象,回收时让存活的对象都向⼀端移动,直接清理端边界外的内存分代收集算法:将java堆分为新⽣代和⽼年代,垃圾回收时,新⽣代每次都有⼤量对象死去,所以采⽤复制算法,⽼年代存活的对象较多,使⽤标记-清除或标记-整理9、常见的垃圾收集器?Serial收集器:单线程收集器ParNew收集器:,新⽣代收集器,Serial收集器的多线程版本Parallel Scavenge收集器:新⽣代收集器,使⽤复制算法。是⽤来实现最⼤吞吐量(代码运⾏时间/(代码运⾏时间+垃圾收集的时间))Serial Old收集器:Serial收集器的⽼年代版本Parallel Old收集器:ParNew收集器的⽼年代版本(⼀般使⽤Parallel Scavenge + Parallel Old)CMS收集器:是⼀种以获取最短停顿时间为⽬标的收集器。分为4个步骤:初始标记,并发标记,重新标记,并发清除采⽤ 标记-清除算法(1)初始标记:标记GC Root能直接关联到的对象 (stop the world)(2)并发标记:进⾏Gc Root Tracing的过程(3)重新标记:修正并发标记期间⽤户线程序继续⼯作⽽导致的标记的变动(stop the world)(4)并发清除:清除未被标记的对象G1收集器:可以独⽴的管理整个gc堆。步骤:初始标记,并发标记,最终标记,筛选回收(⾸先对各个Region价值排序)从整体上看是:标记-整理算法 , 从局部上看(两个region)采⽤复制算法10、什么情况下对象进⼊⽼年代⼤对象直接进⼊⽼年代(需要⼤量连续空间的对象)。常见的⼤对象就是很长的字符串和数组长期存活的对象进⼊⽼年代。每个对象有⼀个年龄计数器。每熬过⼀次moinor gc,年龄就增加⼀岁。当年龄增加到⼀定程度(默认为15)就会晋升到⽼年代(通过MaxTenuringThreshold设置)。动态年龄判断:如果survivor空间某个年龄对象的⼤⼩⼤于survivor空间的⼀半,年龄⼤于或等于的直接进⼊⽼年代空间分配担保:复制算法中,survivor中⽆法容纳的对象将通过分配担保机制直接进⼊⽼年代11、什么时候进⾏GC程序员不能控制具体的时间Eden区满了会触发minor GC,⽼年代满或调⽤执⾏Full GC三、Tomcat篇1、Tomcat 有哪⼏种Connector 运⾏模式(优化)?bio:传统的Java I/O操作,同步且阻塞IO。nio:JDK1.4开始⽀持,同步阻塞或同步⾮阻塞IO。aio(nio.2):JDK7开始⽀持,异步⾮阻塞IO。apr:Tomcat将以JNI的形式调⽤Apache HTTP服务器的核⼼动态链接库来处理⽂件读取或⽹络传输操作,从⽽⼤⼤地 提⾼Tomcat对静态⽂件的处理性能。2、Tomcat容器是如何创建servlet类实例?⽤到了什么原理?当容器启动时,会读取在webapps⽬录下所有的web应⽤中的⽂件,然后对xml⽂件进⾏解析,并读取servlet注册信息。然后,将每个应⽤中注册的servlet类都进⾏加载,并通过反射的⽅式实例化。(有时候也是在第⼀次请求时实例化)在servlet注册时加上如果为正数,则在⼀开始就实例化,如果不写或为负数,则第⼀次请求实例化。3、Tomcat内存调优内存⽅式的设置是在中,调整⼀下JAVA_OPTS变量即可,因为后⾯的启动参数会把JAVA_OPTS作为JVM的启动参数来处理。具体设置如下:JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4"
其各项参数如下:-Xmx3550m:设置JVM最⼤可⽤内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代⼤⼩为2G。整个堆⼤⼩=年轻代⼤⼩ + 年⽼代⼤⼩ + 持久代⼤⼩。持久代⼀般固定⼤⼩为64m,所以增⼤年轻代后,将会减⼩年⽼代⼤⼩。此值对系统性能影响较⼤,Sun官⽅推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈⼤⼩。JDK5.0以后每个线程堆栈⼤⼩为1M,以前每个线程堆栈⼤⼩为256K。更具应⽤的线程所需内存⼤⼩进⾏调整。在相同物理内存下,减⼩这个值能⽣成更多的线程。但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成,经验值在3000~5000左右。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年⽼代的⽐值(除去持久代)。设置为4,则年轻代与年⽼代所占⽐值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的⼤⼩⽐值。设置为4,则两个Survivor区与⼀个Eden区的⽐值为2:4,⼀个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代⼤⼩为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最⼤年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进⼊年⽼代。对于年⽼代⽐4、垃圾回收策略调优垃圾回收的设置也是在中,调整JAVA_OPTS变量。具体设置如下:JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100" 具体的垃圾回收策略及相应策略的各项参数如下:串⾏收集器(JDK1.5以前主要的回收⽅式)-XX:+UseSerialGC:设置串⾏收集器并⾏收集器(吞吐量优先)⽰例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:+UseParallelGC:选择垃圾收集器为并⾏收集器。此配置仅对年轻代有效。即上述配置下,年轻代使⽤并发收集,⽽年⽼代仍旧使⽤串⾏收集。
-XX:ParallelGCThreads=20:配置并⾏收集器的线程数,即:同时多少个线程⼀起进⾏垃圾回收。此值最好配置与处理器数⽬相等。
-XX:+UseParallelOldGC:配置年⽼代垃圾收集⽅式为并⾏收集。JDK6.0⽀持对年⽼代并⾏收集
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果⽆法满⾜此时间,JVM会⾃动调整年轻代⼤⼩,以满⾜此值。
-XX:+UseAdaptiveSizePolicy:设置此选项后,并⾏收集器会⾃动选择年轻代区⼤⼩和相应的Survivor区⽐例,以达到⽬标系统规定的最低相应时间或者收集频率等,此值建议使⽤并⾏收集器时,⼀直打开。
并发收集器(响应时间优先)
⽰例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC:设置年⽼代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代⼤⼩最好⽤-Xmn设置。
-XX:+UseParNewGC: 设置年轻代为并⾏收集。可与CMS收集同时使⽤。JDK5.0以上,JVM会根据系统配置⾃⾏设置,所以⽆需再设置此值。
-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进⾏压缩、整理,所以运⾏⼀段时间以后会产⽣“碎⽚”,使得运⾏效率降低。此值设置运⾏多少次GC以后对内存空间进⾏压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年⽼代的压缩。可能会影响性能,但是可以消除碎⽚
5、添加JMS远程监控对于部署在局域⽹内其它机器上的Tomcat,可以打开JMX监控端⼝,局域⽹其它机器就可以通过这个端⼝查看⼀些常⽤的参数(但⼀些⽐较复杂的功能不⽀持),同样是在JVM启动参数中配置即可,配置如下:-=false -ticate=false
-me=192.168.71.38 设置JVM的JMS监控监听的IP地址,主要是为了防⽌错误的监听成127.0.0.1这个内⽹地址
-=1090 设置JVM的JMS监控的端⼝
-=false 设置JVM的JMS监控不实⽤SSL
-ticate=false 设置JVM的JMS监控不需要认证6、请解释Tomcat中使⽤的连接器是什么?在Tomcat中,使⽤了两种类型的连接器:HTTP连接器:它有许多可以更改的属性,以确定它的⼯作⽅式和访问功能,如重定向和代理转发AJP连接器:它以与HTTP连接器相同的⽅式⼯作,但是他们使⽤的是HTTP的AJP协议。AJP连接器通常通过插件技术mod_jk在Tomcat中实现7、解释什么是Tomcat Valve?Tomcat Valve——Tomcat 4引⼊的新技术,它允许您将Java类的实例链接到⼀个特定的Catalina容器。8、说明Tomcat配置了多少个Valve?Tomcat配置了四种类型的Valve:访问⽇志远程地址过滤远程主机过滤器客户请求记录器9、请说明NAT协议的⽬的是什么?NAT协议的⽬的是将私有IP地址从公共IP地址隐藏起来,并给组织提供⼀定的安全性。四、MyBatis篇1、Mybaits的优点:基于SQL语句编程,相当灵活,不会对应⽤程序或者数据库的现有设计造成任何影响,SQL写在XML⾥,解除sql与程序代码的耦合,便于统⼀管理;提供XML标签,⽀持编写动态SQL语句,并可重⽤。与JDBC相⽐,减少了50%以上的代码量,消除了JDBC⼤量冗余的代码,不需要⼿动开关连接;很好的与各种数据库兼容(因为MyBatis使⽤JDBC来连接数据库,所以只要JDBC⽀持的数据库MyBatis都⽀持)。能够与Spring很好的集成;提供映射标签,⽀持对象与数据库的ORM字段关系映射;提供对象关系映射标签,⽀持对象关系组件维护。2、MyBatis框架的缺点:SQL语句的编写⼯作量较⼤,尤其当字段多、关联表多时,对开发⼈员编写SQL语句的功底有⼀定要求。SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。3、MyBatis与Hibernate有哪些不同?Mybatis和hibernate不同,它不完全是⼀个ORM框架,因为MyBatis需要程序员⾃⼰编写Sql语句。Mybatis直接编写原⽣态sql,可以严格控制sql执⾏性能,灵活度⾼,⾮常适合对关系数据模型要求不⾼的软件开发,因为这类软件需求变化频繁,⼀但需求变化要求迅速输出成果。但是灵活的前提是mybatis⽆法做到数据库⽆关性,如果需要实现⽀持多种数据库的软件,则需要⾃定义多套sql映射⽂件,⼯作量⼤。Hibernate对象/关系映射能⼒强,数据库⽆关性好,对于关系模型要求⾼的软件,如果⽤hibernate开发可以节省很多代码,提⾼效率。4、#{}和${}的区别是什么#{}是预编译处理,${}是字符串替换。Mybatis在处理#{}时,会将sql中的#{}替换为?号,调⽤PreparedStatement的set⽅法来赋值;Mybatis在处理${}时,就是把${}替换成变量的值。使⽤#{}可以有效的防⽌SQL注⼊,提⾼系统安全性。5、Mybatis是如何进⾏分页的?分页插件的原理是什么?Mybatis使⽤RowBounds对象进⾏分页,它是针对ResultSet结果集执⾏的内存分页,⽽⾮物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使⽤分页插件来完成物理分页。分页插件的基本原理是使⽤Mybatis提供的插件接⼝,实现⾃定义插件,在插件的拦截⽅法内拦截待执⾏的sql,然后重写sql,根据dialect⽅⾔,添加对应的物理分页语句和物理分页参数。6、Xml映射⽂件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?、、、、,加上动态sql的9个标签,其中为sql⽚段标签,通过标签引⼊sql⽚段,为不⽀持⾃增的主键⽣成策略标签。7、最佳实践中,通常⼀个Xml映射⽂件,都会写⼀个Dao接⼝与之对应,请问,这个Dao接⼝的⼯作原理是什么?Dao接⼝⾥的⽅法,参数不同时,⽅法能重载吗?Dao接⼝,就是⼈们常说的Mapper接⼝,接⼝的全限名,就是映射⽂件中的namespace的值,接⼝的⽅法名,就是映射⽂件中MappedStatement的id值,接⼝⽅法内的参数,就是传递给sql的参数。Mapper接⼝是没有实现类的,当调⽤接⼝⽅法时,接⼝全限名+⽅法名拼接字符串作为key值,可唯⼀定位⼀个MappedStatement,举例:udentById,可以唯⼀找到namespace为tDao下⾯id = findStudentById的MappedStatement。在Mybatis中,每⼀个、、、标签,都会被解析为⼀个MappedStatement对象。Dao接⼝⾥的⽅法,是不能重载的,因为是全限名+⽅法名的保存和寻找策略。Dao接⼝的⼯作原理是JDK动态代理,Mybatis运⾏时会使⽤JDK动态代理为Dao接⼝⽣成代理proxy对象,代理对象proxy会拦截接⼝⽅法,转⽽执⾏MappedStatement所代表的sql,然后将sql执⾏结果返回。8、Mybatis动态sql是做什么的?都有哪些动态sql?能简述⼀下动态sql的执⾏原理不?Mybatis动态sql可以让我们在Xml映射⽂件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。其执⾏原理为,使⽤OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。9、Mybatis是如何将sql执⾏结果封装为⽬标对象并返回的?都有哪些映射形式?第⼀种是使⽤标签,逐⼀定义列名和对象属性名之间的映射关系。第⼆种是使⽤sql列的别名功能,将列别名书写为对象属性名,⽐如T_NAME AS NAME,对象属性名⼀般是name,⼩写,但是列名不区分⼤⼩写,Mybatis会忽略列名⼤⼩写,智能找到与之对应对象属性名,你甚⾄可以写成T_NAME AS NaMe,Mybatis⼀样可以正常⼯作。有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使⽤反射给对象的属性逐⼀赋值并返回,那些找不到映射关系的属性,是⽆法完成赋值的。10、Mybatis是否⽀持延迟加载?如果⽀持,它的实现原理是什么?Mybatis仅⽀持association关联对象和collection关联集合对象的延迟加载,association指的就是⼀对⼀,collection指的就是⼀对多查询。在Mybatis配置⽂件中,可以配置是否启⽤延迟加载lazyLoadingEnabled=true|false。它的原理是,使⽤CGLIB创建⽬标对象的代理对象,当调⽤⽬标⽅法时,进⼊拦截器⽅法,⽐如调⽤().getName(),拦截器invoke()⽅法发现()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调⽤(b),于是a的对象b属性就有值了,接着完成().getName()⽅法的调⽤。这就是延迟加载的基本原理。当然了,不光是Mybatis,⼏乎所有的包括Hibernate,⽀持延迟加载的原理都是⼀样的。11、Mybatis的Xml映射⽂件中,不同的Xml映射⽂件,id是否可以重复?不同的Xml映射⽂件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践⽽已。原因就是namespace+id是作为Map
@Before 注解使⽤这个Advice。返回之后通知(After Retuning Advice): 在连接点正常结束之后执⾏的Advice。例如,如果⼀个⽅法没有抛出异常正常返回。通过@AfterReturning 关注使⽤它。抛出(异常)后执⾏通知(After Throwing Advice): 如果⼀个⽅法通过抛出异常来退出的话,这个Advice就会被执⾏。通⽤@AfterThrowing 注解来使⽤。后置通知(After Advice): ⽆论连接点是通过什么⽅式退出的(正常返回或者抛出异常)都会执⾏在结束后执⾏这些Advice。通过
@After注解使⽤。围绕通知(Around Advice): 围绕连接点执⾏的Advice,就你⼀个⽅法调⽤。这是最强⼤的Advice。通过
@Around注解使⽤。9、 什么是Spring的依赖注⼊依赖注⼊,是IOC的⼀个⽅⾯,是个通常的概念,它有多种解释。这概念是说你不⽤创建对象,⽽只需要描述它如何被创建。你不在代码⾥直接组装你的组件和服务,但是要在配置⽂件⾥描述哪些组件需要哪些服务,之后⼀个容器(IOC容器)负责把他们组装起来。10、有哪些不同类型的IOC(依赖注⼊)⽅式?构造器依赖注⼊:构造器依赖注⼊通过容器触发⼀个类的构造器来实现的,该类有⼀系列参数,每个参数代表⼀个对其他类的依赖。Setter⽅法注⼊:Setter⽅法注⼊是容器通过调⽤⽆参构造器或⽆参static⼯⼚ ⽅法实例化bean之后,调⽤该bean的setter⽅法,即实现了基于setter的依赖注⼊。11、哪种依赖注⼊⽅式你建议使⽤,构造器注⼊,还是 Setter⽅法注⼊?两种依赖⽅式都可以使⽤,构造器注⼊和Setter⽅法注⼊。最好的解决⽅案是⽤构造器参数实现强制依赖,setter⽅法实现可选依赖。12、 如何给Spring 容器提供配置元数据?这⾥有三种重要的⽅法给Spring 容器提供配置元数据。XML配置⽂件。基于注解的配置。基于java的配置。六、SpringMVC⾯试题整理七、Redis篇1、什么是Redis?简述它的优缺点?Redis本质上是⼀个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进⾏操作,定期通过异步操作把数据库数据flush到硬盘上进⾏保存。因为是纯内存操作,Redis的性能⾮常出⾊,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的出⾊之处不仅仅是性能,Redis最⼤的魅⼒是⽀持保存多种数据结构,此外单个value的最⼤限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以⽤来实现很多有⽤的功能。⽐⽅说⽤他的List来做FIFO双向链表,实现⼀个轻量级的⾼性 能消息队列服务,⽤他的Set可以做⾼性能的tag系统等等。另外Redis也可以对存⼊的Key-Value设置expire时间,因此也可以被当作⼀ 个功能加强版的memcached来⽤。 Redis的主要缺点是数据库容量受到物理内存的限制,不能⽤作海量数据的⾼性能读写,因此Redis适合的场景主要局限在较⼩数据量的⾼性能操作和运算上。2、Redis⽀持哪⼏种数据类型?String、List、Set、Sorted Set、hashes3、Redis有哪⼏种数据淘汰策略?noeviction:返回错误当内存限制达到并且客户端尝试执⾏会让更多内存被使⽤的命令(⼤部分的写⼊指令,但DEL和⼏个例外)allkeys-lru: 尝试回收最少使⽤的键(LRU),使得新添加的数据有空间存放。volatile-lru: 尝试回收最少使⽤的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。allkeys-random: 回收随机的键使得新添加的数据有空间存放。vlatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。4、⼀个字符串类型的值能存储最⼤容量是多少?512M5、为什么Redis需要把所有数据放到内存中?Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的⽅式将数据写⼊磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。 如果设置了最⼤使⽤的内存,则数据已有记录数达到内存限值后不能继续插⼊新值。6、Redis集群最⼤节点个数是多少?16384个。7、Redis有哪些适合的场景?会话缓存(Session Cache)最常⽤的⼀种使⽤Redis的情景是会话缓存(session cache)。⽤Redis缓存会话⽐其他存储(如Memcached)的优势在于:Redis提供持久化。当维护⼀个不是严格要求⼀致性的缓存时,如果⽤户的购物车信息全部丢失,⼤部分⼈都会不⾼兴的,现在,他们还会这样吗?幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使⽤Redis来缓存会话的⽂档。甚⾄⼴为⼈知的商业平台Magento也提供Redis的插件。全页缓存(FPC)除基本的会话token之外,Redis还提供很简便的FPC平台。回到⼀致性问题,即使重启了Redis实例,因为有磁盘的持久化,⽤户也不会看到页⾯加载速度的下降,这是⼀个极⼤改进,类似PHP本地FPC。再次以Magento为例,Magento提供⼀个插件来使⽤Redis作为全页缓存后端。此外,对WordPress的⽤户来说,Pantheon有⼀个⾮常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页⾯。队列Reids在内存存储引擎领域的⼀⼤优点是提供 list 和 set 操作,这使得Redis能作为⼀个很好的消息队列平台来使⽤。Redis作为队列使⽤的操作,就类似于本地程序语⾔(如Python)对 list 的 push/pop 操作。如果你快速的在Google中搜索“Redis queues”,你马上就能找到⼤量的开源项⽬,这些项⽬的⽬的就是利⽤Redis创建⾮常好的后端⼯具,以满⾜各种队列需求。例如,Celery有⼀个后台就是使⽤Redis作为broker,你可以从这⾥去查看。排⾏榜/计数器Redis在内存中对数字进⾏递增或递减的操作实现的⾮常好。集合(Set)和有序集合(Sorted Set)也使得我们在执⾏这些操作的时候变的⾮常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个⽤户–我们称之为“user_scores”,我们只需要像下⾯⼀样执⾏即可:当然,这是假定你是根据你⽤户的分数做递增的排序。如果你想返回⽤户及⽤户的分数,你需要这样执⾏:ZRANGE user_scores 0 10 WITHSCORESAgora Games就是⼀个很好的例⼦,⽤Ruby实现的,它的排⾏榜就是使⽤Redis来存储数据的,你可以在这⾥看到。发布/订阅最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使⽤场景确实⾮常多。我已看见⼈们在社交⽹络连接中使⽤,还可作为基于发布/订阅的脚本触发器,甚⾄⽤Redis的发布/订阅功能来建⽴聊天系统!10、Redis集群⽅案应该怎么做?都有哪些⽅案?twemproxy,⼤概概念是,它类似于⼀个代理⽅式,使⽤⽅法和普通redis⽆任何区别,设置好它下属的多个redis实例后,使⽤时在本需要连接redis的地⽅改为连接twemproxy,它会以⼀个代理的⾝份接收请求并使⽤⼀致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使⽤⽅式简便(相对redis只需修改连接端⼝),对旧项⽬扩展的⾸选。 问题:twemproxy⾃⾝单端⼝实例的压⼒,使⽤⼀致性hash后,对redis节点数量改变时候的计算值的改变,数据⽆法⾃动移动到新的节点。codis,⽬前⽤的最多的集群⽅案,基本和twemproxy⼀致的效果,但它⽀持在 节点数量改变情况下,旧节点数据可恢复到新hash节点。redis cluster3.0⾃带的集群,特点在于他的分布式算法不是⼀致性hash,⽽是hash槽的概念,以及⾃⾝⽀持节点设置从节点。具体看官⽅⽂档介绍。在业务代码层实现,起⼏个毫⽆关联的redis实例,在代码层,对key 进⾏hash计算,然后去对应的redis实例操作数据。 这种⽅式对hash层代码要求⽐较⾼,考虑部分包括,节点失效后的替代算法⽅案,数据震荡后的⾃动脚本恢复,实例的监控,等等。11、Redis⽀持的Java客户端都有哪些?官⽅推荐⽤哪个?Redisson、Jedis、lettuce等等,官⽅推荐使⽤Redisson。12、Jedis与Redisson对⽐有什么优缺点?Jedis是Redis的Java实现的客户端,其API提供了⽐较全⾯的Redis命令的⽀持;Redisson实现了分布式和可扩展的Java数据结构,和Jedis相⽐,功能较为简单,不⽀持字符串操作,不⽀持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使⽤者对Redis的关注分离,从⽽让使⽤者能够将精⼒更集中地放在处理业务逻辑上。13、说说Redis哈希槽的概念?Redis集群没有使⽤⼀致性hash,⽽是引⼊了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责⼀部分hash槽。14、Redis集群的主从复制模型是怎样的?为了使在部分节点失败或者⼤部分节点⽆法通信的情况下集群仍然可⽤,所以集群使⽤了主从复制模型,每个节点都会有N-1个复制品.15、Redis集群会有写操作丢失吗?为什么?Redis并不能保证数据的强⼀致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。16、Redis中的管道有什么⽤?⼀次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,⽽不⽤等待回复,最后在⼀个步骤中读取该答复。这就是管道(pipelining),是⼀种⼏⼗年来⼴泛使⽤的技术。例如许多POP3协议已经实现⽀持这个功能,⼤⼤加快了从服务器下载新邮件的过程。17、怎么理解Redis事务?事务是⼀个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执⾏。事务在执⾏的过程中,不会被其他客户端发送来的命令请求所打断。事务是⼀个原⼦操作:事务中的命令要么全部被执⾏,要么全部都不执⾏。18、Redis事务相关的命令有哪⼏个?MULTI、EXEC、DISCARD、WATCH19、Redis如何做内存优化?尽可能使⽤散列表(hashes),散列表(是说散列表⾥⾯存储的数少)使⽤的内存⾮常⼩,所以你应该尽可能的将你的数据模型抽象到⼀个散列表⾥⾯。⽐如你的web系统中有⼀个⽤户对象,不要为这个⽤户的名称,姓⽒,邮箱,密码设置单独的key,⽽是应该把这个⽤户的所有信息存储到⼀张散列表⾥⾯.⼋、Mongodb篇1、使⽤mongodb的优点⾯向⽂件⾼性能⾼可⽤易扩展可分⽚对数据存储友好2、MongoDB⽀持存储过程吗?如果⽀持的话,怎么⽤?MongoDB⽀持存储过程,它是javascript写的,保存在表中。3、MySQL和MongoDB之间最基本的区别是什么?关系型数据库与⾮关系型数据库的区别,即数据存储结构的不同。4、如何理解MongoDB中的GridFS机制,MongoDB为何使⽤GridFS来存储⽂件?GridFS是⼀种将⼤型⽂件存储在MongoDB中的⽂件规范。使⽤GridFS可以将⼤⽂件分隔成多个⼩⽂档存放,这样我们能够有效的保存⼤⽂档,⽽且解决了BSON对象有限制的问题。5、如果⼀个分⽚(Shard)停⽌或很慢的时候,发起⼀个查询会怎样?如果⼀个分⽚停⽌了,除⾮查询设置了“Partial”选项,,否则查询会返回⼀个错误。如果⼀个分⽚响应很慢,MongoDB会等待它的响应。6、 Mongodb 的索引注意事项?索引很有⽤,但是它也是有成本的——它占内存,让写⼊变慢;mongoDB通常在⼀次查询⾥使⽤⼀个索引,所以多个字段的查询或者排序需要复合索引才能更加⾼效;复合索引的顺序⾮常重要在⽣成环境构建索引往往开销很⼤,时间也不可以接受,在数据量庞⼤之前尽量进⾏查询优化和构建索引;避免昂贵的查询,使⽤查询分析器记录那些开销很⼤的查询便于问题排查;通过减少扫描⽂档数量来优化查询,使⽤explai对开销⼤的查询进⾏分析并优化;索引是⽤来查询⼩范围数据的,不适合使⽤索引的情况:
发布评论