面试笔记【自己总结】

    将自己遇到的有含量且常见的面试题分类统计

  

-----------------------linux相关------------------------ 

 在这里总结自己面试这么多次遇到的linux相关的面试题:

1.linux启动过程是咋样的?

 大致分为五步:

(1)内核引导:

  读入/boot下的内核文件

(2)运行init

  读取/etc下面的配置文件(init进程)

 (3)系统初始化:

   读取/etc/rc.d/rcX.d/目录下面的文件  (开机启动的一些服务)

[root@iz2ze46xi6pjjj69ailg9lz bin]# cd /etc/rc.d/
[root@iz2ze46xi6pjjj69ailg9lz rc.d]# ls
init.d  rc0.d  rc1.d  rc2.d  rc3.d  rc4.d  rc5.d  rc6.d  rc.local

  /etc/rc[0-6].d是/etc/rc.d/rc[0-6].d的软连接:    /etc/init.d是/etc/rc.d/init.d的一个软连接

(4)建立终端:

  建立6个终端   tty1-tty6

(5)用户登录

 三种登录方式:

  ssh   命令行  图形化界面

 

2.linux的文件权限以及如何改变文件权限?

(1)文件权限解释:

首先看一组linux文件权限:

[root@iz2ze46xi6pjjj69ailg9lz ~]# ll
total 307576
-rw-r--r--  1 root  root     356682 Mar 14 23:40 ~
-rw-r--r--  1 root  root    8961394 Feb  1 15:59 exam1.31.sql
-rw-r--r--  1 root  root   14744393 Jan 27 13:50 exam.sql
-rw-r--r--  1 root  root  213608341 Jan 27 22:19 Exam.war
drwxrwxr-x 11 17608 17608      4096 Aug 22  2017 mbedtls-2.6.0
-rw-r--r--  1 root  root    1958070 Mar 14 23:53 mbedtls-2.6.0-gpl.tgz
-rw-r--r--  1 root  root   75281701 Mar 26 22:02 mongodb-linux-x86_64-3.2.9.tgz
drwxr-xr-x  3 root  root       4096 Mar 14 23:46 ss
-rw-r--r--  1 root  root         40 Sep  1  2017 test
drwxr-xr-x  3 root  root       4096 Jan 26 20:51 tomcat项目
drwxr-xr-x  2 root  root       4096 Oct 28 10:51 ww
drwxr-xr-x  3 root  root       4096 Dec 16 16:48 自己的练习

在Linux中第一个字符代表这个文件是目录、文件或链接文件等等。

  • 当为[ d ]则是目录
  • 当为[ - ]则是文件;
  • 若是[ l ]则表示为链接文档(link file);
  • 若是[ b ]则表示为装置文件里面的可供储存的接口设备(可随机存取装置);
  • 若是[ c ]则表示为装置文件里面的串行端口设备,例如键盘、鼠标(一次性读取装置)。

  接下来的字符中,以三个为一组,且均为『rwx』 的三个参数的组合。其中,[ r ]代表可读(read)、[ w ]代表可写(write)、[ x ]代表可执行(execute)。 要注意的是,这三个权限的位置不会改变,如果没有权限,就会出现减号[ - ]而已。

  r=读取属性  //值=4
  w=写入属性  //值=2
  x=执行属性  //值=1

 

 (2)改变文件的运行权限:     chmod  命令:

权限范围的表示法如下:

u User,即文件或目录的拥有者;
g Group,即文件或目录的所属群组;
o Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围;
a All,即全部的用户,包含拥有者,所属群组以及其他用户;
r 读取权限,数字代号为“4”;
w 写入权限,数字代号为“2”;
x 执行或切换权限,数字代号为“1”;
- 不具任何权限,数字代号为“0”;
s 特殊功能说明:变更文件或目录的权限。

 

chmod(选项)(参数)

选项

-c或——changes:效果类似“-v”参数,但仅回报更改的部分;
-f或--quiet或——silent:不显示错误信息;
-R或——recursive:递归处理,将指令目录下的所有文件及子目录一并处理;
-v或——verbose:显示指令执行过程;
--reference=<参考文件或目录>:把指定文件或目录的所属群组全部设成和参考文件或目录的所属群组相同;
<权限范围>+<权限设置>:开启权限范围的文件或目录的该选项权限设置;
<权限范围>-<权限设置>:关闭权限范围的文件或目录的该选项权限设置;
<权限范围>=<权限设置>:指定权限范围的文件或目录的该选项权限设置;

参数

权限模式:指定文件的权限模式;
文件:要改变权限的文件。

 

例子:

chmod u+x,g+w f01  //为文件f01设置自己可以执行,组员可以写入的权限
chmod u=rwx,g=rw,o=r f01
chmod 764 f01
chmod a+x f01  //对文件f01的u,g,o都设置可执行属性

 

文件的属主和属组属性设置

chown user:market f01  //把文件f01给uesr,添加到market组
ll -d f1  查看目录f1的属性

 

 

 

 3.如何设置一个服务开机启动?

   开机服务自启动就是将一可执行文件放到/etc/init.d/目录下,并在/etc/rc.d/rc[0-6].d或者/etc/rc[0-5].d目录下创建软连接。

     /etc/rc[0~6].d其实是/etc/rc.d/rc[0~6].d的软连接,主要是为了保持和Unix的兼容性才做此策

  • 创建可执行脚本文件
  • 赋予文件运行权限
chmod +x XXX.sh

 

  • 创建软连接

 可以手动创建软连接或者chkconfig创建连接。

(1)手动在rc[0-6].d创建软连接:

  在rc0.d-rc6.d目录下分别创建文件连接。  

  第一个字符是S,系统在启动的时候,运行脚 本test2,就会添加一个start参数,告诉脚本,现在是启动模式。同时在rc0.d和rc6.d目录下,创建名字为K90test2的 文件连接,第一个字符为K,系统在关闭系统的时候,会运行test2,添加一个stop,告诉脚本,现在是关闭模式。

ln -s /etc/rc.d/init.d/test2 /etc/rc.d/rc2.d/S99test2
ln -s /etc/rc.d/init.d/test2 /etc/rc.d/rc3.d/S99test2
ln -s /etc/rc.d/init.d/test2 /etc/rc.d/rc5.d/S99test2
ln -s /etc/rc.d/init.d/test2 /etc/rc.d/rc0.d/K01test2
ln -s /etc/rc.d/init.d/test2 /etc/rc.d/rc6.d/K01test2

 

 (2)chkconfig创建软连接:

chkconfig --add test2

 

 

脚本的前三行如下:(脚本前面三行格式固定)

#!/bin/sh
#chkconfig: 2345 80 90
#description:test2

第一行,告诉系统使用的shell,所有的shell脚本都是这样。
第 二行,chkconfig后面有三个参数2345,80和90告诉chkconfig程序,需要在rc2.d~rc5.d目录下,创建名字为 S80test2的文件连接,连接到/etc/rc.d/init.d目录下的的test2脚本。

 

验证服务:

 chkconfig --list

 

 参考:http://www.cnblogs.com/qlqwjy/p/7746184.html

 4.linux的运行级别是咋样的?

 

 

5.linux下面想要查询一个日志文件的最后20行

 head,tail分别显示文件开头和结尾内容

例如查看文件前20行:

  head -n 20 xxx.txt 

 

查看文件最后20行

  tail -n 20 xxx.txt

 

 查看文件中间一段,你可以使用sed命令,如: 

sed -n '8,9p' catalina.2018-03-15.log

这样你就可以只查看文件的第8行到第9行。  

 

如果需要实时查看日志:

tail -f catalina.out 

 

6.linux的shell类型

sh(全称 Bourne Shell): 是UNIX最初使用的 shell,而且在每种 UNIX 上都可以使用。
Bourne Shell 在 shell 编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种 shell。
bash(全称 Bourne Again Shell): LinuxOS 默认的,它是 Bourne Shell 的扩展。
与 Bourne Shell 完全兼容,并且在 Bourne Shell 的基础上增加了很多特性。可以提供命令补全,命令编辑和命令历史等功能。它还包含了很多 C Shell 和 Korn Shell 中的优点,有灵活和强大的编辑接口,同时又很友好的用户界面。
csh(全称 C Shell): 是一种比 Bourne Shell更适合的变种 Shell,它的语法与 C 语言很相似。
Tcsh: 是 Linux 提供的 C Shell 的一个扩展版本。
Tcsh 包括命令行编辑,可编程单词补全,拼写校正,历史命令替换,作业控制和类似 C 语言的语法,他不仅和 Bash Shell 提示符兼容,而且还提供比 Bash Shell 更多的提示符参数。
ksh (全称 Korn Shell): 集合了 C Shell 和 Bourne Shell 的优点并且和 Bourne Shell 完全兼容。
pdksh: 是 Linux 系统提供的 ksh 的扩展。

 

 

7.Linux开放端口

/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT

 

最后可以加个  service iptables save  永久保存

 

---------------------Java基础相关--------------------

0.Java所有的new操作都是在堆中创建对象,Java的下标除了JDBC获取结果集和PrepareStatement设置参数的时候从1开始,基本上所有的下标都是从0开始。

1.static关键字的用法:(从五方面解释)

  • 用来修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享;
  • 用来修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类;
  • 静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键)

可以用于处理只执行一次的代码,例如:hibernate种SessionFactory的创建,mybatis的SqlSessionFactory的创建

  • 静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便。

import static java.lang.System.out;

out.println(HibernateUtils.openSession());

  • 静态内部类   用法   

 

2.Java中final,finally,finalize的区别

 (1)final可以修饰类、方法、变量

  • 修饰类表示类不可以被继承
  • 修饰方法表示此方法不可以被重写(覆盖)但是可以被重载
  • 修饰变量表示变量不可变(引用不可变--也就是不可以重新指向另一个对象,但是引用内容可以变),而且static final 经常用作常量处理。

 

  (2)finally的使用:---通常用于try..catch..之后关闭一些IO流等操作

  1. try语句没有被执行,如在try语句之前就返回了,这样finally语句就不会执行;因此说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。

  2. 如果在try代码块中执行System.exit(0)语句;那么将终止Java虚拟机JVM,因此,finally语句也不会被执行到。

  3. finally块的语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句可能影响也可能不影响try或catch中return已经确定的返回值,如果返回值类型为传址类型(String与8种包装类型除外),则影响;传值类型与String与8种基本数据类型的包装类型,则不影响。若finally里也有return语句则覆盖try或catch中的return语句直接返回(当然也会覆盖 throw )。

package cn.qlq.test;

public class FinallyTest {

    public static void main(String[] args) {
        System.out.println(test1());
        System.out.println(test2());
    }

    public static String test1() {
        String s = "s1";
        try {
            int i = 1 / 0;
            s = "s2";
            return s;
        } catch (Exception e) {
            s = "s3";
            return s;
        } finally {
            s = "s4";
        }
    }

    public static Person test2() {
        Person p = new Person();
        p.setName("old");
        try {
            int i = 1 / 0;
            return p;
        } catch (Exception e) {
            p.setName("exception");
            return p;
        } finally {
            p.setName("finally");
        }
    }
}

结果:

s3
Person [age=0, name=finally]

 

 finally块的语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句可能影响也可能不影响try或catch中return已经确定的返回值,如果返回值类型为传址类型,则影响;传值类型(8种基本类型)与8种基本数据类型的包装类型与String(不可变类)不影响。若finally里也有return语句则覆盖try或catch中的return语句直接返回。

 

面试宝典解释的原因如下:

  程序在执行到return时首先会把返回值存到一个指定的位置(JVM中的slot),其次与执行finally块,最后再返回。如果finally中有return语句会以finally的return为主,相当于普通程序中的return结束函数。如果没有return语句,则会在finally执行完之后弹出slot存储的结果值并且返回,如果是引用类型则finally修改会影响结果,如果是基本数据类型或者不可变类不会影响返回结果。

补充: finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到

public class FinallyTest {

    public static void main(String[] args) {
        test0();
    }

    private static void test0() {
        try {
            test1();
        } finally {
            System.out.println("test0 finally");
        }
    }

    private static void test1() {
        System.out.println("test1 start");
        test2();
        System.out.println("test1 end");
    }

    private static void test2() {
        try {
            System.out.println("test2 start");
            int i = 1 / 0;
            System.out.println("test2 end");
        } catch (Throwable ex) {
            System.out.println("test2 exception");
            throw ex;
        }

    }
}

结果:

test1 start
test2 start
test2 exception
123456
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at FinallyTest.test2(FinallyTest.java:29)
    at FinallyTest.test1(FinallyTest.java:22)
    at FinallyTest.test0(FinallyTest.java:14)
    at FinallyTest.main(FinallyTest.java:9)

  (3)finalize()析构方法的使用

  finalize()在JVM回收对象的时候会调用该对象的此方法,用于垃圾回收的时候处理一些事情

 

3.  switch支持的数据类型:

  记住一条,可以转为int型的都可以作为switch case的数据类型,switch表达式后面的数据类型只能是byte(1),short(2),char(2),int(4)四种整形类型(这些基本类型的包装类型是不支持的),枚举类型和java.lang.String类型(从java 7才允许),不能是boolean类型。

4.java基本数据类型的长度以及数据类型转换以及初值

 Java一共提供了8种原始的数据类型(byte、short、int、long、float、double、char、boolean),这些数据类型不是对象,而是Java中不同于类的特殊类型,这些基本类型的数据变量在声明之后就会立即在栈上被分配空间。除了这些基本类型外,其他类型都是引用类型,这类变量在声明时不会被分配内存空间,只是存储了一个内存地址。

 

注意:

1) 在Java中,默认声明的小数是double类型的,而整数默认是int类型。

2) 在Java中,null不是一个合法的Object实例,所以编译器并没有为其分配内存,它仅仅用于表明该引用目前没有指向任何对象。null是将引用变量的值全部置0。

 

注意:如果是临时变量(方法内部变量)不会赋初值,只有成员属性才会赋初值。

另外注意,引用类型占用四个字节。

 

5.java多态----覆盖(重写概念)

覆盖就是父类的变量指向子类的对象,调用变量的方法实际上是调用子类的覆盖了父类的方法,这也是多态的体现(面试官说重写是多态,重载是不是还在研究中。。。。。。。)。

        Parent p1 = new Child1();
        Parent p2 = new Child2();
        p1.method1();//调用Child1类重写了父类的method1方法
        p2.method1();//调用Child2类重写了父类的method1方法

多态的三个必要条件:

  • 继承
  • 重写
  • 父类引用指向子类对象

 

多态的实现方式:

  重写、接口、抽象方法和抽象类

 

 6.  java异常

Error和Exception(运行时异常和检查异常)  参考https://www.cnblogs.com/qlqwjy/p/7816290.html

 

补充:一个线程运行时发生异常会怎样?

  如果异常没有被捕获该线程将会停止执行。 (这个在线程池中也会体现,线程池中当达到最大线程数某个线程执行中异常未被捕获而结束时,会重新创建一个线程)

 

7.  Java的Integer常量池和String常量池

  String s1 = new String("1"); 是在堆中创建一个String对象,并将s1指向该对象;String s2 = new String("1"); 又在堆中创建一个String对象,并将s2指向该对象;

  String s3 = "1";   在常量池创建一个对象1,并将s3指向该对象;String s4 = "1"  的时候常量池已经有1,所以不会再创建对象,也就是s3与s4指向同一个对象。

 

  Integer i1 = new Integer(1)的时候是在Java堆中创建一个Integer对象,i1指向堆中的对象,i1与常量池没关系。

  Integer i3=1;的时候是从常量池中查找值为1的常量,i3指向该常量,Integer常量池的大小是-128到127

 

8.深复制与浅复制区别

浅复制:被赋值的对象与原对象都含有相同的值,而所有对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅赋值所考虑的对象,而不复制它所引用的对象。

深赋值:被复制的对象的所有变量都有与原对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被赋值的新对象,而不再是原来的那些被引用的对象。换言之,深复制把复制的对象所引用的对象都复制了一遍。

 

9.值传递与引用传递

  1)值传递:方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。

  2)引用传递(指针传递):也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,所以方法执行中形式参数的改变将会影响实际参数。(包装类型是引用传值,但是由于String和8种包装类型的不可变性,所以操作形参相当于重新创建对象并赋给形参,不影响实参),数组也是引用传递。

  在Java中,原始数据类型在传递参数时都是按值传递,而包装类型在传递参数是是按引用传递,但包装类型在进行计算的时候会自动拆箱,。

  对象在函数调用传参的时候是引用传递(基本数据类型值传递),"="赋值也是引用传递(基本数据类型值传递)

10.可变类与不可变类

  不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的很多不可变类:Interger、Long和String(8种基本数据类型的包装类和String都是不可变类)等。不可变类的意思是一旦这个对象创建之后其引用不会改变,每次重新赋值会新增一个对象。不可变类是实例创建后就不可以改变成员遍历的值。这种特性使得不可变类提供了线程安全的特性但同时也带来了对象创建的开销,每更改一个属性都是重新创建一 个新的对象。例如String s = "s1",s = "s2"实际上是创建了两个对象,第二次将其值指向新的"s2".。

  可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类

11.创建对象的五种方式

  

 

12.  一个有返回值的方法必须有return语句吗?

  如果把return和throw放在一起,直接会提示错误,"Unreachable statement"(无法被执行)。 retrun和throw都是使程序跳出当前的方法。所以有throw 的时候会退出当前程序也就不需要return。

如下代码编译是正确的:

    public String getName() {
        throw new RuntimeException();
    }

 

 

13.  java中transient关键字的作用

  transient关键字修饰的字段在序列化的时候不会被序列化,此关键字只能修饰字段,不能修饰方法。我们用第三方序列化工具如fastjson序列化的时候这些字段会被跳过。

  比如一些敏感的信息如密码等不需要被序列化。

  参考jdk中HashMap的源码,很多字段被设计为transient。   

 

14. java中实现两个接口的方法

  将一个接口的具体实现设计为实现类的私有内部类、且实现类实现另一个接口,如下:

public interface Interface1 {

    void ope1();

}

 

public interface Interface2 {

    void ope2();

}

 

public class Class1 implements Interface2 {

    private class InnerClass1 implements Interface1 {

        @Override
        public void ope1() {
            System.out.println("ope1");
        }

    }

    @Override
    public void ope2() {
        System.out.println("ope2");
    }

    public Interface1 getInterface1() {
        return new InnerClass1();
    }
}

 

public class Client {

    public static void main(String[] args) {
        Class1 class1 = new Class1();
        class1.ope2();
        class1.getInterface1().ope1();
    }

}

结果:

ope2
ope1

 

15.为什么循环中使用字符串+效率很低

  字符串相加编译器是生成一个StringBuilder对象,然后append之后调用toString方法进行拼接,所以循环中多次+会生成多个StringBuilder对象以及多次append、toString。创建对象本身就需要在堆中创建对象,相对费时。
  StringBuilder 的原理是预先分配了一个足够大小的缓冲区,然后循环的过程就是往缓冲区里填充数据,比使用“+”做字符串连接的效率要高很多。

16 如果spring事务失效的可能原因是什么

 参考:https://www.cnblogs.com/javastack/p/12160464.html

 

---------------------多线程相关-------------------------

参考:http://www.cnblogs.com/xrq730/p/5060921.html

1.Thread和Runnable的区别和联系

2.多次start一个线程会怎么样:  可以看出如果线程状态不是新建就会抛出非法状态异常。也就是多次start会抛出非法状态异常。

    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

 

3.线程有哪些状态

    public enum State {
        NEW,

        RUNNABLE,

        BLOCKED,

        WAITING,

        TIMED_WAITING,

        TERMINATED;
    }

 

1、新建状态NEW

  new了线程但是没有开始执行,比如: Thread t1 = new Thread();t1就是一个新建状态的线程。

2、可运行状态RUNNABLE

  new出来线程,调用start()方法即处于RUNNABLE状态了。处于RUNNABLE状态的线程可能正在Java虚拟机中运行,也可能正在等待处理器的资源,因为一个线程必须获得CPU的资源后,才可以运行其run()方法中的内容,否则排队等待

3、阻塞BLOCKED

  如果某一线程正在等待监视器锁,以便进入一个同步的块/方法,那么这个线程的状态就是阻塞BLOCKED

4、等待WAITING

  某一线程因为调用不带超时的Object的wait()方法、不带超时的Thread的join()方法、LockSupport的park()方法,就会处于等待WAITING状态

5、超时等待TIMED_WAITING

  某一线程因为调用带有指定正等待时间的Object的wait()方法、Thread的join()方法、Thread的sleep()方法、LockSupport的parkNanos()方法、LockSupport的parkUntil()方法,就会处于超时等待TIMED_WAITING状态

6、终止状态TERMINATED

  线程调用终止或者run()方法执行结束后,线程即处于终止状态。处于终止状态的线程不具备继续运行的能力。

 

 

---------------------Web前端相关-------------------------

1.JS闭包概念

 

---------------------JavaWeb相关-------------------------

 

---------------------数据结构相关--------------------------

---------------------数据库相关--------------------------

1. mysql索引失效的场景

(1)where 中用or,除非or也加索引
(2)对于复合索引,如果不使用前列,后续列也将无法使用
(3)like查询是以%开头,左模糊
(4)存在索引列的数据类型隐形转换,则用不上索引,比如列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
(5)where 子句里对索引列上有数学运算,用不上索引
(6)where 子句里对有索引列使用函数,用不上索引
(7)如果mysql估计使用全表扫描要比使用索引快,则不使用索引。比如数据量极少的表

(8)in 查询也是不走索引。(其实这个是个错误的说法,in在某些情况下会走、某些情况下不会走索引。  有些情况下Mysql会判断不走索引更快,会进行全表扫描,比如数据量只有几条的时候;在数据量大的时候in会走索引)

测试如下:

(1) 查看索引

show index from user;

 (2)  数据量只有两条的时候测试: 这时候没有走索引,走的全表扫描

 (3) 数据量大的时候进行的测试(数据量到达千条以上)

 测试二: 子查询测试

2. 索引的最左匹配、回表查询以及解决办法

非聚集索引的btree叶子节点中存储的是当行数据的PK。所以为了取到具体数据,则需要通过PK回到聚集索引里去查询数据。着就叫回表查询。扫描了2次索引树。所以效率相对较低。

比如查询: 

select username, fullname from user where username = 'zs';

其执行过程可能是:第一遍先通过非聚集索引定位到主键值,然后第二遍再通过聚集索引定位到具体行记录。这就是所谓的回表查询,即先定位主键值,再根据主键值定位行记录,性能相对于只扫描一遍聚集索引树的性能要低一些。explain如下:

解决办法:  

  索引覆盖就是为了避免回表查询的一种解决方案。见名知意,就是查询的所有列均被所使用的索引的列给到覆盖(可以是单列索引也可以是联合索引)。因为索引中已经包含了要查询的字段的值,因此查询的时候直接返回索引中的字段值就可以了,不需要再到表中查询,避免了对主键索引的二次查询,也就提高了查询的效率。

 第一种就是上面点查询只查询username 列,这样会索引覆盖,不会再回表查询

第二种就是建立联合索引:

alter table user add  index index_user_username_fullname(username, fullname)

-》查看索引

 

 -》分析上面语句

 

 

---------------------Java框架相关-------------------------

posted @ 2018-03-27 17:44  QiaoZhi  阅读(585)  评论(0编辑  收藏  举报