1.在回答面试官的时候技术知识点回答方式:这边我说一下对技术的理解 1,2 3,4 综上所述,得出什么样的结论
2.== 和equals的区别:
String s1 = new String(“abc”)
String s2 = new String(“abc”)
S1 ==s2(false)
S1.equals(s2)(true)
Person p1=new Person(“abk”);
Person p2=new Person(“abk”);
P1==p2 false
P1.equals (p2) false
- ==既可以比较基本类型,又可以比较引用类型
- 对于基本类型比较的是值,对于引用类型比较的是地址值
- == 比较的new 出来的永远是false
- Equals到底比较什么,要看他是否被重写,equals如果按照出厂默认状态,也就是没有被重写的情况下,equals为Object类型 ,Person为默认的Object类里面的Equals方法,而Object类中equals的源码为 public boolean equals(Object obj){return (this == obj),也就是说equals在默认情况下为 == ;
★综上所述: ==既可以比较基本类型,又可以比较引用类型,对于基本类型比较的是值,对于引用类型比较的是地址值;
equals要看是否被重写过,如果被重写过,首先equals只能比较引用类型,如果被重写过,请按照重写的具体情况去判断,如果没被重写过,就默认为 ==。
String类的equals是被重写过的,并且String类在日常开发中经常被使用,以至于形成了equals是比较值的错误观念
3.HashSet set = new HashSet();
Person p1 = new Person(1001,"a");
Person p2 = new Person(1002,"b");
set.add(p1);
set.add(p2);
p1.name="c";
set.remove(p1);
System.out.println(set);//求重写person的hashcode和equals后打印的值,和没重写后打印的值
set.add(new Person(1001,"c"));
System.out.println(set);//求重写person的hashcode和equals后打印的值,和没重写后打印的值
set.add(new Person(1001,"a"));
System.out.println(set);//求重写person的hashcode和equals后打印的值,和没重写后打印的值
(1).HashSet原理:HashSet底层是HashMap,所以可以说没有HashSet这一说,HashSet无序不可重复,若要实现HashSet无序和不可重复就必须要重写HashCode和equals方法,相信你懂德!
(2)在集合类里面 我们来判断对象是否重复,其中对于hashSet和HashMap来将HashCode最重要,按照sun公司的规范,若复写equals就必须复写hashcode和toString,后来因为toString相对于而言作用伤害小一些,可以通过get方法获得,所以就被忽略了。
若要实现业务的需求,就需要相等的对象必须要有相等的散列码(hashcode)
4. equals的重写,何时需要重写equals?
当一个类有自己特有的“逻辑相等”的概念,当改写equals的时候总要改写hashcode方法,根据一个类只改写了equals方法以后,两个截然不同的实例可能是在逻辑上相等的,但是根据Object.Hashcode方法,他们仅仅是两个对象,因此违反了“相等的对象必须具有相等的散列码”。因此重写equals的时候一般都需要重写hashcode方法
5.eclipse中复写hashcode的时候,为什么参数值是31
为了优化,计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位即可!选择31是因为31是个素数,
在存储计算Hash地址的时候,我们希望尽量减少有相同的hash地址,就是减少所谓的“冲突”。
因为任何N*31就可以被JVM优化为(n<<5)-n,移位和减法的操作效率要比乘法的操作效率高的多,对左移 虚拟机里面都有做相关的优化,并且31只占用5Bits!
6.jvm 内存堆里面分:
新生区,老年区,永久区。新生区里又分:伊甸园区,幸存0区,幸存1区
String s1 = new String(“abc”);
String s2 =”abc”;
String s3= new String(“abc”);
S1==s2 false;
S1==s3 false;
S3==s2 false;
创建了三个对象
String StringBuffer StringBuider
尽量对于String少用+=;如果String经常变化,要用StringBuffer或builder的append
String s4 =”java”;
String s5=”ja”;
String s6 = “va”; 堆
S4==”java”; true
S4==(S5+S6);false
S4==”ja”+S6;false
常量找池,变量找堆,只要有加号,就会生成新的对象
7.什么是多态?
父类的引用可以指向子类的实例
8.java里面通过方法的重写和方法的重载来体现多态是否正确?
这句话是废话,完全错误,可以看看java编程思想第4版英文版上面显示标题:这是一种非常错误和傻逼的说法。多态父类的引用指向子类的实例,说明多态的运用一定是父类到子类,就是说多态的前提一定要有继承,写个动物类,写个带着重量的构造方法,再写个带着重量和年龄的构造方法,构造方法也是方法重载的一种,只有孤独的一个类,没有其他的引用类,你给我讲哪来的多态。所以方法的重写才是多态的体现,很多书都写错了,以java编程思想为主
9.多态是编译时行为还是运行时行为?
运行时行为。String 框架就是良好的体现。Ctx.getBean(“xx”),提示
10.传值问题
1.对于基本类型传值,永远是传一份复印件过去,原件不动
2.引用类型为String类型值不变
3.引用类型为其他类型值改变
11.静态加载
- New Son():
会打印3,6,2,1,5,4从父到子静态先行,普通代码块的优先级高于构造
- 再 new Son()
2,1,5,4,静态代码块只加载一次
- new father();
2,1 普通代码块的优先级高于构造
12.方法重写:
子类不能抛出比父类更高的异常
子类允许重写是用更高的修饰符,
一般改错的时候会用到
13.Try ---catch的时候 :
考关于数据库或JDBC的时候,关于Try ---catch的时候,往往没有关闭数据库或JDBC的有关操作
14.serializable接口的理解:
不要说什么用于序列化,是个空的接口方法之类的。小白都知道!要更深层次的去解释serializable!
比如:1.实现了serializable接口的对象,可以将它们转换成一系列字节,并可在以后完全恢复回原来的样子。这一过程也可以用在网络进行。这意味着序列化机制能自动补偿操作系统之间的差异。换句话说,可以先在windows机器上创建一个对象, 对其序列化,然后通过网络发送给一台uinx机器,然后在那里准确无误的重新“装配”。不必关心数据在不同机器上如何表现,也不必关心字节的顺序或其他任何细节。
2.考察你公司框架如何封装的:如 public Object getObjById(Serializable id );
往往用于Base类中,来替代public Object getObjById(String id )或public Object getObjById(Integer id ).
所以遇到这个问题你要小心了,永远不要回答表面上的,要答人家想听的和别人希望你不知道的。
15.关于业务流程
面试的时候往往会问到你们公司的业务流程是什么?基础框架是什么?日常开发当中如果以一个登录页面为例,从头做到尾,你们前端用到什么?Controller层用到什么,service层用到什么,接口和接口之间怎么调的,模块和模块之间又是怎么传的,中间传的用了哪些JSON的解析工具
16.
谈谈你对
HashMap
中
put/get
方法的认识?如果了解再谈谈
HashMap
的扩容机制?默认大小是多少?什么是负载因子?什么是吞吐临界值?
首先声明一点:我所写的均基于JDK1.7版本,至于1.8版本,hashmap又产生了红黑树之类的底层数据
1. 首先当我们new HashMap();
底层默认的初始容量的源码为1<<4 也就是16;
默认的负载因子为0.75f;也就是说当剩下上一个容量的1/4的容量时(临界吞吐值=容量*负载因子),以2倍的比率扩容 (底层用resize = 2 * table.length);
map里面装的是数组类型的entry<?,?>,也就是说当new HashMap();相当于entry<?,?>[]={};
如果没往里面装东西的时候,只是声明了一个引用,没有开辟具体的空间;当调用Put方法的时候才声明了一个名为table的数组.
2.HashMap利用Put装元素,先用HashCode比较是否有相同的散列码,然后再用equals进行比较,所谓的比较只是比较的K值,跟value值没用任何关系,根据特定的算法进行换算所存放的位置,所以HashMap为无序不可重复的,而HashMap底层为数组和单项数据entry链表(底层Put上明显写着永远指向next),后加的数据在链表头,如果HashMap中存的K值为null,null默认只会存放在数组的零号下角标位置(也是就是所谓的置顶)
3.get 利用hash值和table.length进行计算寻找table的下角标,然后再根据 == 或equals比较元素,如果此时刚好为下角标所在的值时,直接取出,如果不是再去列表中一一比对
综上所述:
1 HashSet
底层是采用
HashMap
实现
2.
集合里面放置的永远是对象的引用而不是对象本身
3.
当你在
HashSet
里
add
对象的时候,实际是
HashMap
里面
put
了
key-value
键值对,其中
key
就是你
add
进来的对象,
value
是一个固定的
Object
常量
4. HashMap
底层是个
Entry
类型的,名字叫
table
的数组
5.put:
当程序试图将一个
key-value
对放入
HashMap
中时,程序首先根据该
key
的
hashCode()
返回值决定该
Entry
的存储位置:如果两个
Entry
的
key
的
hashCode()
返回值相同,那它们的存储位置相同。如果这两个
Entry
的
key
通过
equals
比较返回
true
,新添加
Entry
的
value
将覆盖集合中原有
Entry
的
value
,但
key
不会覆盖。如果这两个
Entry
的
key
通过
equals
比较返回
false
,新添加的
Entry
将与集合中原有
Entry
形成
Entry
链,而且新添加的
Entry
位于
Entry
链的头部
——
具体说明继续看
addEntry()
方法的说明。
17.如果HashMap有线程安全的问题如何解决?
建议多看看Arrays,Collections,和JUC 并发包
1.Collections.
synchronizedMap(
Map<K,V> m);90后多谈及工具类Collections,里面好多很好用到的
2.
java.util.concurrent类 ConcurrentHashMap<K,V>;不允许有null值,实质是HashTable,表面为HashMap
18.
ArrayList底层是什么?扩容机制?
1.ArrayList 查询快,增删慢,底层为Object[]数组,初始容量为10,1.5倍的扩容机制,当你进公司的时候肯定会看到new ArrayList(某个值),因为ArrayList扩容要不断CopyOf来搬家,如果作为程序员,知道自己差不多要存多少值,就一次性声明ArrayList的长度,这样可以达到很好的优化,一好的程序员再实现功能的同时又很好的优化了性能,是个有前途的程序员! 但是在工作中如果想不到同时优化性能就先完成这个功能,编程就是循环迭代的一个过程,先量化,再优化!
所以可以这么回答:
ArrayList
以数组实现,允许重复。超出限制时会增加
50%
的容量(
grow()
方法中实现,如下所示),每次扩容都底层采用
Arrays.
copyOf
()
复制到新的数组,因此最好能给出数组大小的预估值。默认第一次插入元素时创建数组的大小为
10.
19.
请问ArrayList/LinkedList/Vector的区别?谈谈你的理解?Vector和ArrayList的最大区别?
1、ArrayList和LinkedList的区别
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
2、ArrayList和Vector的区别
Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于强同步类。因此开销就比ArrayList要大,访问要慢。正常情况下,大多数的Java程序员使用ArrayList而不是Vector,因为同步完全可以由程序员自己来控制。Vector每次扩容请求其大小的2倍空间,而ArrayList是1.5倍。Vector还有一个子类Stack.
20.
Servlet中service、doGet、doPost的区别?
1.当实现HttpServlet以后如果只是实现deGet和doPost方法的时候,实际上是调用了service,再通过Service进行分配查找doGet和doPost方法,当页面发送get请求是的时候就去找doget,当为post请求的时候就去找doPost,但是当三个方法同时实现的话,发送请求只找service,就不再访问doget和doPost了
21.
请求转发和重定向有什么区别?(web开发必须要用的)
Answer:IE
地址栏是否变化?参数可否取得?发送了几次请求
1.以servlet为例子,RequestDispatcher接口(请求转发器接口)
- RequestDispatcher实例对象是由Servlet引擎创建的,它用于包装一个要被其他资源调用的资源(例如:Servlet、HTML文件、JSP文件等),并可以通过其中的方法将客户端的请求转发给所包装的资源
- RequestDispatcher接口中定义了两个方法:forward() 和 include() 方法
- forward() 和 include() 方法接受的两个参数必须是传递给当前 Servlet 的 service() 方法的那两个ServletRequest和ServletResponse对象,或者是对它们进行了包装的ServletRequestWrapper或ServletResponseWrapper对象
- 获取RequestDispathcer对象的方法
- ServletContext.getRequestDispatcher() (参数只能是以 “/” 开头的路径)
- ServletContext.getNamedDispatcher()
- ServletRequest.getRequestDispatcher() (参数可以是不以 “/” 开头的路径)
2. sendRedirect方法实现请求重定向
- sendRedirect() 方法不仅可以重定向到当前应用程序中的其他资源,它还可以重定向到同一个站点上的其他应用程序的资源,甚至是使用绝对URL重定向到其他站点的资源
- 如果传递给sendRedirect() 方法的相对URL以 “/” 开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录
综上所述:
(1)请求重定向和请求转发的本质区别
请求的转发只发出一次请求
请求的重定向发出两次请求
具体:
1)
请求的转发:地址栏是初次发出的请求的地址
请求的重定向:地址栏不再是初次发出的请求的地址,地址栏为最后响应的地址
2)
请求的转发:在最终的Servlet中,request对象和中转的request是同一个对象
请求的重定向:在最终的Servlet中,request对象和中转的request不是同一个对象,其是两次请求
3)
请求的转发:只能转发给当前WEB应用的资源
请求的重定向:可以重定向到任何资源
4)
请求的转发:“/”代表WEB资源的根目录
请求的重定向:“/”代表当前WEB站点的根目录
关于request的属性值操作,请求的转发可以获得其属性值,请求的重定向不能获得
MVC设计模式的本质就是请求的转发
(2)请求重定向和请求转发的详细比较
RequestDispatcher.forward方法只能讲请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源
如果传递给HttpServletResponse.sendRedirect 方法的相对URL以 “/” 开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以 “/” 开头,它是相对于当前WEB应用程序的根目录
调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变为重定向的目标URL;调用RequestDispatcher.forward方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变
HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求
RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器内部发生了转发行为
RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程
22.servlet生命周期?
生命周期:从创建到销毁的过程。
servlet运行在servlet容器、JSP容器(Tomcat服务器)、受服务器管理的。
服务决定如何创建对象和销毁。
写一个Servlet;
实现Servlet接口:
构造器
init();初始化
service();服务
destroy();销毁
第一次请求Servlet:
创建对象(构造器),并初始化(init),调用service()
以后每次请求Servlet:
只执行Service方法。
服务器关闭,项目卸载
执行销毁方法 destroy();销毁
23.
Servlet
线程相关
Answer:多线程+单实例,后续都是同一个对象为我们服务。写servlet的时候一定不要去定义成员变量,除非它是只读的,尽量缩小范围定义局部变量。
24.
HTTP
协议相关的内容
Http是一个属于应用层的面向对象的协议,http协议的主要特点可概括为:
1.支持客户/服务器模式
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET,HEAD,POST。每种方法规定了客户与服务器联系的类型不同。由于http协议简单,使得Http服务器的程序规模小,因而通信速度很快
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即刻断开连接。采用这种方式可以节省传输时间
5.无状态:HTTP协议是个无状态协议。无状态是指客户端和服务器端不必保存对方的详细信息,服务器端只需处理当前的request请求,不必了解之前request所做的事
25.
多线程编码,两句正确有用的废话
1.线程 操纵 资源
三个售票员 卖 票
线程 操纵 资源
2.高内聚低耦合(用在哪,怎么用)
把自己收拾干净,少麻烦别人。尽量的内聚是高,也就是说,对这个资源的操作,最好是这个资源自身带着对自己的操纵方法,然后自己对外暴露出去供其他线程调用
26.获得线程对象的方法有几种?
1.继承Thread
2.实现Runnable
3.实现Callable接口
:和Runnable的区别:
Runnable 无返回值,不抛出异常
Callable 有返回值,抛出异常
好处:(1)有返回值可以获得线程运行的结果,抛出异常可以获得线程死亡的详细情况
(2) 在进行大数据运算的时候Callable是必用的
4.线程池获得
综上所述:一定要给面试官讲清楚:一共有四种方法,传统的JDK1.5之前只有两种:分别是继承Thread和实现Runnable,但是1.5版本以后又增加了两种实现Callable接口和通过线程池获得,之前我所在的公司主要用后两种,这个时候绝对会给你面试上加分,如果这个公司表现出一脸茫然的样子要不是面试官技术陈旧就是这个公司技术落后,如果面试官表现出平淡,就证明他觉得你真学过,这时候你要好好聊聊后两种和前面的区别
27.线程加锁的方法
1.同步代码块
2.同步方法
3.lock
28.线程唤醒方法
1。wait ---notify
2。 Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
condition.await();
condition.signalAll();
使用唤醒机制必须用while判断是否是虚假唤醒
lock.lock();
try {
while (num!=1) {
condition.await();
}
Thread.sleep(200);
--num;
System.err.println(Thread.currentThread().getName() + "执行了num=:"
+ (num) + "的数字");
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
29.线程的八锁
•
一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个 synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
•
锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
•
加个普通方法后发现和同步锁无关
•
换成两个对象后,不是同一把锁了,情况立刻变化。
•
都换成静态同步方法后,情况又变化
•
所有的非静态同步方法用的都是同一把锁——实例对象本身
,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
所有的静态同步方法用的也是同一把锁——类对象本身
,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!
30.JUC(并发包之线程池的使用)
巧妙使用Executors解决获取线程对象问题
1.ExecutorService executorService = Executors.newFixedThreadPool(5);
一个线程池里创建了五个固定的线程来干活
executorService.submit(Callable)
提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
不要忘记关闭线程池 shutdown
2.Executors.newSingleThreadExecutor()
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
executorService.submit(Callable)
提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
不要忘记关闭线程池 shutdown
3.Executors.newCachedThreadPool();
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
executorService.submit(Callable)
提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
不要忘记关闭线程池 shutdown
4.Executors.newScheduledThreadPool(int corePoolSize);
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
创建并执行在给定延迟后启用的 ScheduledFuture。
参数:
callable - 要执行的功能
delay - 从现在开始延迟执行的时间
unit - 延迟参数的时间单位(为枚举)
返回:
可用于提取结果或取消的 ScheduledFuture
抛出:
RejectedExecutionException - 如果无法安排执行该任务
NullPointerException - 如果 callable 为 null
service.shutdown永远不要忘记关闭线程池
31.解决GIT或SVN冲突
SVN或Git冲突分为四种冲突:
(1)内容冲突
(2)逻辑冲突:我引用着的时候突然别另一个程序员修改
(3)树冲突:分支合并时易发生,绝对不能删除,要人工干预,手动修 改
1.解决Git冲突
解决合并中的冲突
如果执行自动合并没有成功的话,git会在索引和工作树里设置一个特殊的状态,提示你如何解决合并中出现的冲突。
有冲突(conflicts)的文件会保存在索引中,除非你解决了问题并且更新了索引,否则执行git commit都会失败:
$ git commit
file.txt: needs merge
如果执行git status会显示这些文件没有合并(unmerged),这些有冲突的文件里面会添加像下面的冲突标识符:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
你所需要的做是就是编辑解决冲突,解决冲突就是在"<<< === >>>"包围的内容中找出那些需要保留的部分,删除掉不需要的,
接着把冲突标识符删掉,再执行下面的命令,就解决了冲突:
$ git add file.txt
$ git commit -s -m "........."
注意:提交注释里已经有一些关于合并的信息了,通常是用这些默认信息,但是你可以添加一些你想要的注释。
上面这些就是你要做一个简单合并所要知道的,但是git提供更多的一些信息来帮助解决冲突
2.解决SVN冲突:
1、在commit 时提示有一些文件发生了冲突,但这些文件自己确实没有改过,可能是编译时产生了问题;对于这种不需要修改的发生了冲突,则可以用 revert 放弃修改。
丢弃对一个文件的修改:
$ svn revert foo.c
reverted foo.c
如果你希望恢复一整个目录的文件,可以使用--depth=infinity选项:
$ Svn revert --depth=infinity ./path
2、在 commit 时发生冲突的文件,自己需要修改,但是其他人早于你提交了此文件的其他修改,这就产生了冲突。
foo.c
$ svn merge foo.c
合并文件后,在文件中会有 ">>>>>>> .mine",表示自己新增的修改,"<<<<<<<< .r270" 表示版本270中新增的修改,确认这些修改后,将这些符号去掉。
$ svn resolved foo.c 表示冲突 resolved
32.你在项目中碰到SVN或者Git冲突了你如何解决的?•你在项目 中碰到SVN或者Git冲突了你如何解决的?
1.有冲突的故障现象是那种尖尖括号
2.一般而言,从我们公司代码规范和管理经验而言的话,我们是不允许删除,只允许人工合并,而且要现场解决,那么基本上我们在Git或Svn上面解决冲突的话呢,有两种基本的解决方案:第一种,人工合并带冲突的,比如说,错开一位或错开一行;第二种,我把我本地的拷贝一份,我永远不会和服务器冲突,只要冲突了就直接覆盖掉,然后再把本地的代码沾到里面
33.
Mybatis中动态sql拼装<if>开发错误:
•Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named XXX' in 'class java.lang.XXX'的解决办法
34.什么是索引:
A:Mysql官方对索引的定义为:索引是帮助高效获取数据的数据结构,索引可以大大提高查询的检索速度。
创建索引时,你需要确保该索引是应用在SQL 查询语句的条件(一般作为WHERE
子句的条件)。实际上,索引也是一张表,该表保存了主键与索引字段,并指向
实体表的记录。索引是可以提高查询速度,但过多的使用索引将会造成滥用。
因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降
低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,
MySQL不仅要保存数据,还要保存一下索引文件。
建立索引会占用磁盘空间的索引文件。
35.
哪些情况下索引不建
1.
表记录太少。
2.
经常增删改的表。
3.
数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
36.
索引失效和EXPLAIN查询分析
1 少用or,用它来连接时会索引失效
2 where子句的查询条件里有!=,mysql将无法使用索引。
3使用了mysql的函数时索引将无效
4使用like查询%开头
5字符串不加单引号索引失效
6 复合索引不使用第一列
比如有一条语句是这样的:select * from users where area=’beijing’ and age=22;如 果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率, 但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age, salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀 特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
37.索引不足或缺点
1. 提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件
2. 建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快
3. 索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句
38.explain字段解释
Id : 语句编号
select_type: select类型
table: 显示这一句SQL是关于哪张表的
type: 显示了连接使用了哪种类别,有无使用索引
possible_keys: MySQL可能使用哪个索引
key: key列显示MySQL实际决定使用的键(索引)
key_len: key_len列显示MySQL决定使用的键长度
ref: ref列显示使用哪个列或常数与key一起从表中选择
rows: rows列显示MySQL认为它执行查询时必须检查的行数
Extra: 该列包含MySQL解决查询的详细信息
39.注意注解版Transactional会有很大的坑
@Transactional可以放在类上,声明readOnly=true,可以方便查找的事务,声明在方法增删改除
但是如果不设置rollback的异常回滚,会默认为是运行时异常,这样的话如果是在像下面的例子中:出现了异常,数据库不回滚
因为输入输出流默认的是编译时异常,所以插入的时候如果输入输出流找不到对应的文件路径也会插入数据库中,所以必须声明rollback为Excption或者更高的异常
40.mybatis xml 配置文件里 #{变量名}与${变量名}的区别是什么?
Mybatis3 防止SQL注入
#{xxx},使用的是PreparedStatement,会有类型转换,所以比较安全;推荐使用#
${xxx},使用字符串拼接,可以SQL注入;
like查询不小心会有漏动,正确写法如下:
Mysql: select * from t_user where name like concat('%', #{name}, '%')
Oracle: select * from t_user where name like '%' || #{name} || '%'
SQLServer: select * from t_user where name like '%' + #{name} + '%'
41.说说难忘的生产故障:
答。高CPU占用
1.TOP,先用TOP确定高耗用的进程ID
2.
通过ps aux | grep PID命令,可以进一步确定是tomcat进程出现了问题。
3.首先显示线程列表 ps -mp pid -o thread ,tid,time
4.将需要的线程ID转换为16进制格式 :printf"%x\n"tid
5.打印线程的堆栈信息:jstack pid|grep tid -a 30
42.
总结下排查
CPU
故障的方法和技巧有哪些:
1、top命令:Linux命令。可以查看实时的CPU使用情况。也可以查看最近一段时间的CPU使用情况。
2、PS命令:Linux命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前CPU使用情况。属于当前状态的采样数据。
3、jstack:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。
4、pstack:Linux命令。可以查看某个进程的当前线程栈运行情况
。
43.Linux服务器性能查看和分析有哪些认识?
1.系统整体性能评估:uptime,top
利用top查看运行了多长时间 ,当前有几个用户连接,负载均衡问题 cpu使用率,交换分区的值
2.cpu性能评估:vmstat r列表示运行和等待cpu时间片的进程数,这个值如果长期大于系统CPU的个数,说 明CPU不足,需要增加CPU。
3.内存性能评估:利用 free 指令监控内存
可用内存/系统物理内存>70%时,内存充足
当小于20%时,需要增加系统内存
4. 磁盘I/O性能评估 :iostat
长期的,超大数据读写,肯定不正常,会影像系统戏能
5.网络性能评估
通过ping查看网络连通性
通过netstat -i组合检测网络接口状况
通过netstat -r组合检测系统的路由表信息
6.查看磁盘剩余空间 df -h