其他分享
首页 > 其他分享> > 面试题(更新于2021.05)

面试题(更新于2021.05)

作者:互联网

目录

JavaSE基础

1.谈谈对OOP的理解

2.JDK 和 JRE 的区别?

3.重写和重载

4.==与equals()的区别?

5.try、catch、finally的执行顺序

6.final 在 java 中有什么作用?

7.基本数据类型有哪些?

8.String底层原理

9.String str="i" 与 String str=new String(“i”) 一样吗?

10.String、StringBuffer、StringBuilder的区别?

11. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

12.如何将字符串反转?

13.String 类的常用方法都有那些?(待补充)

14.抽象类必须要有抽象方法吗?

15.普通类和抽象类有哪些区别?

16.抽象类能使用 final 修饰吗?

17.接口和抽象类

18.java 中 IO 流分为几种?

19.BIO、NIO、AIO 有什么区别?

20.Files的常用方法都有哪些?

集合面试题(常见)

1.集合有哪些?

2.List、Set、Map 的区别?

3.数组和 list 之间的转换

4.ArrayList扩容机制

5.ArrayList 、Vector和LinkedList 的区别?

6.Array 和 ArrayList 有何区别?

7.在 Queue 中 poll()和 remove()有什么区别?

8.如果要保证ArraList线程安全,有几种方式?

9.HashMap与HashTable的区别?

10.HashSet 的实现原理?

11.hashmap的底层原理,会不会产生哈希冲突?

12.HashMap遍历?

13.Set 遍历方法?

14.HashSet和TreeSet的区别?

15.底层数据结构

16.迭代器 Iterator 是什么?

17.Iterator 怎么使用?有什么特点?

18.Iterator 和 ListIterator 有什么区别?

19.怎么确保一个集合不能被修改?

线程面试题(必问)

1.创建线程有哪些方法(4种)?

2.线程的生命周期

3.Runnable和Callable的区别?

4.start()和run()方法有什么区别?

5.线程池有哪些参数

6.线程池有几种(5种)?拒绝策略有几种(4种)?阻塞队列有几种(3种)?

7.死锁

9.volatile与synchronized有什么区别?

10.wait()和sleep()的区别?

11.乐观锁和悲观锁的理解及如何实现,有哪些实现方式?

12.什么是可重入锁(ReentrantLock)?

数据库面试题(必问)

1.索引

2.两种存储引擎

3.数据库优化

4.数据库事务

5.存储过程

7.内连接、左外连接和右外连接的区别?

8.数据库的三大范式?

9.防止sql注入的方法?

spring面试题

1.你对spring的理解?与springmvc和springboot的区别?(经常被问到)

2.spring 的优缺点

3.spring的核心技术(IOC、DI、AOP)

4.Bean的作用域

5.Bean的生命周期

6.Spring 支持的事务管理类型

springmvc面试题

1.什么是Spring MVC ?简单介绍下你对springMVC的理解?

2.SpringMVC的流程?

3.Springmvc的优点

4.Spring MVC的主要组件?

6.SpringMVC怎么样设定重定向和转发的?

7.GET和POST区别?

8.cookie和session的区别?

9.spring mvc中的mvc指的是什么?

10.spring MVC中拦截器与过滤器的用处?加载顺序?

springboot面试题

1.为什么要用springboot?

2.Spring Boot有哪些优点?

3.Spring Boot有哪些核心配置文件

4.Spring Boot 的配置文件有哪几种格式

5.Spring Boot 实现热部署有哪几种方式

6.运行SpringBoot有几种方式?

7.springboot四大特性

8.什么是Swagger?你用Spring Boot实现了吗?

9.什么是FreeMarker模板?

10.springboot常用注解?

mybatis面试题

1.MyBatis 的好处是什么,为什么用mybatis等?(多次被问到)

2.mybatis与hibernate的区别在哪里?(多次被问到)

3.#{}和${}的区别是什么?

4.Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

5.Mybatis是如何进行分页的?分页插件的原理是什么?

6.Mybatis执行批量插入,能返回数据库主键列表吗?

7.mybatis传递参数的方式(4种)?

8.mybatis中模糊查询(mysql)

事务面试题

1.事务的7种传播级别

2.数据隔离级别

3.Java有几种类型的事务?

设计模式

1.设计模式分类

2.设计模式的优点

3.设计模式的六大原则及其含义

4.常见的单例模式以及各种实现方式的优缺点,哪一种最好,手写常见的单例模式

5.设计模式在实际场景的应用(待补充)

6.Spring中用到了哪些设计模式

7.MyBatis中用到了哪些设计模式

8.动态代理

消息队列

1.为什么使用消息队列?(解耦、异步、削峰)

2.使用了消息队列会有什么缺点

3.消息队列如何选型?

4.消息队列由哪些角色组成?

5.消息队列有哪些使用场景?

数据结构

1.排序算法有哪些?

2.以下算法的时间复杂度

3.数组和链表的区别

JVM面试题

1.内存模型以及分区,需要详细到每个区放什么。

2.简述 java 垃圾回收机制?

3.java 类加载过程?

servlet面试题

1.Servlet的生命周期?

2.forward() 与redirect()的区别

3.四种会话跟踪技术

4.Request对象的主要方法

5.Servlet执行时一般实现哪几个方法?

6.GenericServlet和HttpServlet有什么区别?

7.九大内置对象

Linux常用命令(被问到比较少)


JavaSE基础

1.谈谈对OOP的理解

(1)封装:就是隐藏类的内部信息,不允许外部程序直接访问,而是通过getter(获取)和setter(设置)方法完成,提高数据的安全性。

(2)继承:父类的基本特征和行为,子类也会有,子类也可以改变这些特征和行为。

(3)多态:就是多个对象调用同一个方法,可能会得到的是不同的结果。


2.JDK 和 JRE 的区别?

具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。


3.重写和重载

是指同一个类中的多个方法具有相同的名字,参数的数量、类型、顺序不同;与返回值无关


4.==与equals()的区别?

== 解读

对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

代码示例:

String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。

equals 解读

equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。

首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:

class Cat {
    public Cat(String name) {
        this.name = name;
    }
​
    private String name;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}
​
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false

输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:

public boolean equals(Object obj) {
        return (this == obj);
}

原来 equals 本质上就是 ==

那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:

String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true

同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。

总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。


5.try、catch、finally的执行顺序

结论:

举例:
情况1:try{} catch(){}finally{} return;
            显然程序按顺序执行。
情况2:try{ return; }catch(){} finally{} return;
          程序执行try块中return之前(包括return语句中的表达式运算)代码;
         再执行finally块,最后执行try中return;
         finally块之后的语句return,因为程序在try中已经return所以不再执行。
情况3:try{ } catch(){return;} finally{} return;
         程序先执行try,如果遇到异常执行catch块,
         有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
                     最后执行catch块中return. finally之后也就是4处的代码不再执行。
         无异常:执行完try再finally再return.
情况4:try{ return; }catch(){} finally{return;}
          程序执行try块中return之前(包括return语句中的表达式运算)代码;
          再执行finally块,因为finally块中有return所以提前退出。
情况5:try{} catch(){return;}finally{return;}
          程序执行catch块中return之前(包括return语句中的表达式运算)代码;
          再执行finally块,因为finally块中有return所以提前退出。
情况6:try{ return;}catch(){return;} finally{return;}
          程序执行try块中return之前(包括return语句中的表达式运算)代码;
          有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
                       则再执行finally块,因为finally块中有return所以提前退出。
          无异常:则再执行finally块,因为finally块中有return所以提前退出。

最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
                  如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,
                  编译器把finally中的return实现为一个warning。

测试代码:

public class FinallyTest  
{
    public static void main(String[] args) {
	System.out.println(new FinallyTest().test());;
    }

    static int test(){
        int x = 1;
	try{
	    x++;
	    return x;
	}finally{
	    ++x;
	}
    }
}
结果是2。

分析:

在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。 在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果, 因此,即使finally中对变量x进行了改变,但是不会影响返回结果。 它应该使用栈保存返回值。


6.final 在 java 中有什么作用?


7.基本数据类型有哪些?


8.String底层原理

String的底层使用的是char数组。这个char数组和String这个类都是final修饰的,所以不可变。


9.String str="i" 与 String str=new String(“i”) 一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。


10.String、StringBuffer、StringBuilder的区别?


11. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

不对,两个对象的 hashCode()相同,equals()不一定 true。

代码示例:

String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d",  str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));

执行的结果:

str1:1179395 | str2:1179395

false

代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。


12.如何将字符串反转?

使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

示例代码:

// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abcdefg");
System.out.println(stringBuffer.reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abcdefg");
System.out.println(stringBuilder.reverse()); // gfedcba

13.String 类的常用方法都有那些?(待补充)


14.抽象类必须要有抽象方法吗?

不需要,抽象类不一定非要有抽象方法。

示例代码:

abstract class Cat {
    public static void sayHi() {
        System.out.println("hi~");
    }
}

上面代码,抽象类并没有抽象方法但完全可以正常运行。


15.普通类和抽象类有哪些区别?


16.抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,如下图所示,编辑器也会提示错误信息:

final定义抽象类


17.接口和抽象类

Java接口可以理解为一种特殊的类,里面全部是由全局常量公共的抽象方法所组成,是一种规范。

相同点:

不同点:


18.java 中 IO 流分为几种?

字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。


19.BIO、NIO、AIO 有什么区别?


20.Files的常用方法都有哪些?

 

集合面试题(常见)

1.集合有哪些?

Collection接口和Map接口是所有集合框架的父接口:

List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等;

Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等;


2.List、Set、Map 的区别?


3.数组和 list 之间的转换


4.ArrayList扩容机制

ArrayList集合大小如果创建时没有指定,则默认为0,若已经指定集合大小,则初始值为指;

当第一次添加数据的时候,集合大小扩容为10,

第二次及其后续每次按照

int oldCapacity = elementData.length; 
newCapacity = oldCapacity+(oldCapacity>>1)

5.ArrayList 、Vector和LinkedList 的区别?


6.Array 和 ArrayList 有何区别?


7.在 Queue 中 poll()和 remove()有什么区别?

poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。


8.如果要保证ArraList线程安全,有几种方式?

  1. 自己重写一个ArrayList集合类,根据业务一般来说,add/set/remove加锁

  2. 采用synchronized加锁:

    List<Object> list = Collections.synchronizedList(new ArrayList<>());
  3. 采用 ReentrantLock加锁:

    new CopyOnWriteArrayList<>().add("");

9.HashMap与HashTable的区别?


10.HashSet 的实现原理?


11.hashmap的底层原理,会不会产生哈希冲突?

 


12.HashMap遍历?

两种方式遍历:使用EntrySet遍历;使用KeySet 遍历


13.Set 遍历方法?

Set<String> set = new HashSet<String>();  
Iterator<String> it = set.iterator();  
while (it.hasNext()) {  
  String str = it.next();  
  System.out.println(str);  
}  
for (String str : set) {  
      System.out.println(str);  
} 

14.HashSet和TreeSet的区别?

HashSet的存储方式:哈希码算法,加入的对象需要实现hashcode()方法;

TreeSet的存储方式:按序存放,想要有序就要实现Comparable接口

不同点:


15.底层数据结构


16.迭代器 Iterator 是什么?

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。


17.Iterator 怎么使用?有什么特点?

Java中的Iterator功能比较简单,并且只能单向移动:

  1. 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素;

    注意:iterator()方法是java.lang.Iterable接口,被Collection继承。

  2. 使用next()获得序列中的下一个元素;

  3. 使用hasNext()检查序列中是否还有元素;

  4. 使用remove()将迭代器新返回的元素删除。 

Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。


18.Iterator 和 ListIterator 有什么区别?


19.怎么确保一个集合不能被修改?

使用 JDK中java.util.Collections 类,unmodifiable*** 方法赋值原集合。

当再修改集合时,会报错 java.lang.UnsupportedOperationException。从而确保自己定义的集合不被其他人修改。

public class TestCollectionUnmodify {
 
    static List<String> list = new ArrayList<String>();
    static Set<String> set = new HashSet<String>();
    static Map<String, String> map = new HashMap<String, String>();
    
    static {
        list.add("1");
        list.add("2");
        list.add("3");
        
        set.add("1");
        set.add("2");
        set.add("3");
        
        map.put("1", "1");
        map.put("2", "2");
        map.put("3", "3");
    }
    
    public static void main(String[] args) {
        list = Collections.unmodifiableList(list);
        set = Collections.unmodifiableSet(set);
        map = Collections.unmodifiableMap(map);
        listModify();
        setModify();
        mapModify();
    }
    
    public static void listModify() {
        list.add("4");
    }
    
    public static void setModify() {
        set.add("4");
    }
    
    public static void mapModify() {
        map.put("3", "4");
    }
}

 

线程面试题(必问)

1.创建线程有哪些方法(4种)?


2.线程的生命周期

线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。

完整的生命周期图如下:

 


3.Runnable和Callable的区别?


4.start()和run()方法有什么区别?

start()方法被用来启动新创建的线程,而且start()内部调用了run()方法;

run( )方法是一个普通方法,当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动。

  1. start()方法功能介绍

    start()方法来启动线程,真正实现了多线程运行。

    start方法的作用就是将线程由创建状态,变为就绪状态。当线程创建成功时,线程处于创建状态,如果你不调用start( )方法,那么线程永远处于创建状态。调用start( )后,才会变为就绪状态,线程才可以被CPU运行。

  2. start()执行时间

    调用start( )方法后,线程的状态是就绪状态,而不是运行状态(关于线程的状态详细。线程要等待CPU调度,不同的

    JVM有不同的调度算法,线程何时被调度是未知的。因此,start()方法的被调用顺序不能决定线程的执行顺序。

注意:

由于在线程的生命周期中,线程的状态由创建到就绪只会发生一次,因此,一个线程只能调用start()方法一次,多次

启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。


5.线程池有哪些参数

当线程数小于核心线程数时,创建线程;

当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列;

当线程数大于等于核心线程数,且任务队列已满时

     若线程数小于最大线程数,创建线程;

     若线程数等于最大线程数,抛出异常,拒绝任务


6.线程池有几种(5种)?拒绝策略有几种(4种)?阻塞队列有几种(3种)?

1. ExecutorService threadPool = null;
2. threadPool = Executors.newCachedThreadPool();//有缓冲的线程池,线程数 JVM 控制
3. threadPool = Executors.newFixedThreadPool(3);//固定大小的线程池
4. threadPool = Executors.newScheduledThreadPool(2);//一个能实现定时、周期性任务的线程池
5. threadPool = Executors.newSingleThreadExecutor();//单线程的线程池,只有一个线程在工作
6. threadPool = new ThreadPoolExecutor();//默认线程池,可控制参数比较多   
1. RejectedExecutionHandler rejected = null;
2. rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
3. rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
4. rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
5. rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
1. BlockingQueue<Runnable> workQueue = null;
2. workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列,有界
3. workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列,无界
4. workQueue = new SynchronousQueue<>();//无缓冲的等待队列,无界

7.死锁

7.1 什么叫死锁?

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们

都将无法再向前推进。举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有

另外一个线程B,按照先锁b再锁a的顺序获得锁。


7.2 产生死锁的原因?

  1. 因为系统资源不足。

  2. 进程运行推进的顺序不合适。

  3. 资源分配不当等。


7.3 死锁产生的4个必要条件?

  1. 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。

  2. 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。

  3. 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。

  4. 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。


7.4 预防和处理死锁的方法?

(1)尽量不要在释放锁之前竞争其他锁
    一般可以通过细化同步方法来实现,只在真正需要保护共享资源的地方去拿锁,并尽快释放锁,这样可以有效降低  在同步方法里调用其他同步方法的情况
(2)顺序索取锁资源
    如果实在无法避免嵌套索取锁资源,则需要制定一个索取锁资源的策略,先规划好有哪些锁,然后各个线程按照一个顺序去索取,不要出现上面那个例子中不同顺序,这样就会有潜在的死锁问题
(3)尝试定时锁
    在索取锁的时候可以设定一个超时时间,如果超过这个时间还没索取到锁,则不会继续堵塞而是放弃此次任务

解除死锁的方法?

(1)剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
(2)撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。

如何检测死锁?

(1)利用Java自带工具JConsole
(2)Java线程死锁查看分析方法

8.volatile底层是怎么实现的?

当一个变量定义为volatile后,它将具备两种特性:1. 可见性,2. 禁止指令重排序。

可见性:编译器为了加快程序运行速度,对一些变量的写操作会现在寄存器或CPU缓存上进行,最后写入内存。而在这个过程中,变量的新值对其它线程是不可见的。当对volatile标记的变量进行修改时,先当前处理器缓存行的数据写回到系统内存,然后这个写回内存的操作会使其他CPU里缓存了该内存地址的数据无效。
处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存的数据在总线上保持一致。如果一个正在共享的状态的地址被嗅探到其他处理器打算写内存地址,那么正在嗅探的处理器将使它的缓存行无效,在下次访问相同内存地址时,强制执行缓存行填充。

9.volatile与synchronized有什么区别?


10.wait()和sleep()的区别?

(1)sleep()不释放锁,wait()释放锁

(2)sleep()在Thread类中声明的,wait()在Object类中声明

(3)sleep()是静态方法,是Thread.sleep(); wait()是非静态方法,必须由“同步锁”对象调用

(4)sleep()方法导致当前线程进入阻塞状态后,当时间到或interrupt()醒来;wait()方法导致当前线程进入阻塞状态后,由notify或notifyAll()


11.乐观锁和悲观锁的理解及如何实现,有哪些实现方式?

悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如 Java 里面的同步原语 synchronized 关键字的实现也是悲观锁。

乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于 write_condition 机制,其实都是提供的乐观锁。在 Java中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。

乐观锁的实现方式:

使用版本标识来确定读到的数据与提交时的数据是否一致。提交后修改版本标识,不一致时可以采取丢弃和再次尝试的策略。

java 中的 Compare and Swap 即 CAS ,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。 CAS 操作中包含三个操作数 —— 需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置 V 的值与预期原值 A 相匹配,那么处理器会自动将该位置值更新为新值 B。否则处理器不做任何操作。


12.什么是可重入锁(ReentrantLock)?

ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。

在java关键字synchronized隐式支持重入性,synchronized通过获取自增,释放自减的方式实现重入。与此同时,ReentrantLock还支持公平锁和非公平锁两种方式。那么,要想完完全全的弄懂ReentrantLock的话,主要也就是ReentrantLock同步语义的学习:1. 重入性的实现原理;2. 公平锁和非公平锁。

重入性的实现原理

要想支持重入性,就要解决两个问题:

  1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功;

  2. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功。

ReentrantLock支持两种锁:公平锁和非公平锁

何谓公平性,是针对获取锁而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求上的绝对时间顺序,满足FIFO。

 

数据库面试题(必问)

1.索引

1.1 使用场景?

 

1.2 索引分类?

MySQL索引包括普通索引、唯一索引、全文索引、单列索引、多列索引、空间索引

1.3 索引作用和优缺点?

索引就一种特殊的查询表,数据库的搜索可以利用它加速对数据的检索。

它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。

索引可以是唯一的,创建索引允许指定单个列或者是多个列。

缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小

1.4 索引不会命中?

1.5主键和唯一索引?

 


2.两种存储引擎

  1. MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。

  2. InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。

主要区别:


3.数据库优化

(1)根据服务层面:配置mysql性能优化参数;

(2)从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等。

(3)从数据库层面增强性能:优化SQL语句,合理使用字段索引。

(4)从代码层面增强性能:使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力。

(5)减少数据库操作次数,尽量使用数据库访问驱动的批处理方法。

(6)不常使用的数据迁移备份,避免每次都在海量数据中去检索。

(7)提升数据库服务器硬件配置,或者搭建数据库集群。

(8)编程手段防止SQL注入:使用JDBC PreparedStatement按位插入或查询;正则表达式过滤(非法字符串过滤)

sql语句优化

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉 及的列上建立索引。 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使 用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0 3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而 进行全表扫描。 4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索 引而进行全表扫描,如: select id from t where num=10 or num=20 可以这样查询: select id from t where num=10 union all select id from t where num=20 5.in 和 not in 也要慎用,否则会导致全表扫描,如: select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3 6.下面的查询也将导致全表扫描: select id from t where name like ‘%abc%’ 7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用 索引而进行全表扫描。如: select id from t where num/2=100 应改为: select id from t where num=100*2

8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引 而进行全表扫描。如: select id from t where substring(name,1,3)=‘abc’–name以abc开头的id 应改为: select id from t where name like 'abc%' 9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算, 否则系统将可能无法正确使用索引。 10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索 引中的第一个字段作为条件时才能保证系统使用该索引, 否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。 11.不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(…) 12.很多时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b) 用下面的语句替换: select num from a where exists(select 1 from b where num=a.num) 13.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当 索引列有大量数据重复时,SQL查询可能不会去利用索引, 如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也 对查询效率起不了作用。 14.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降 低了 insert 及 update 的效率, 因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑, 视具体情况而定。 一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的 索引是否有必要。 15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会 降低查询和连接的性能,并会增加存储开销。 这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字 型而言只需要比较一次就够了。 16.尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节 省存储空间, 其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 17.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要 返回用不到的任何字段。 18.避免频繁创建和删除临时表,以减少系统表资源的消耗。 19.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当 需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好 使用导出表。 20.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代 替 create table,避免造成大量 log , 以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然 后insert。 21.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。 22.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行, 那么就应该考虑改写。 23.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决 问题,基于集的方法通常更有效。 24.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数 据时。 在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间 允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更 好。 25.尽量避免大事务操作,提高系统并发能力。 26.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合 理。


4.数据库事务


5.存储过程

什么是存储过程?用什么来调用?

存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。
​
如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。
​
调用:  1)可以用一个命令对象来调用存储过程。
​
2)可以供外部程序调用,比如:java程序。

存储过程的优缺点?

优点:
​
1)存储过程是预编译过的,执行效率高。
​
2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。
​
3)安全性高,执行存储过程需要有一定权限的用户。
​
4)存储过程可以重复使用,可减少数据库开发人员的工作量。
​
缺点:移植性差
//创建存储过程
CREATE PROCEDURE userData(
    IN id INT
)
BEGIN
    SELECT * from userdata WHERE userflag = id;
END;
​
其中IN是传进去的变量;
​
drop procedure userData;//销毁这个存储过程
​
call userData(2) //调用存储过程

6.DDL和DML

DDL (Data Definition Language 数据定义语言)

create table 创建表    
alter table  修改表   
drop table 删除表   
truncate table 删除表中所有行    
create index 创建索引   
drop index  删除索引 
当执行DDL语句时,在每一条语句前后,oracle都将提交当前的事务。如果用户使用insert命令将记录插入到数据库后,执行了一条DDL语句(如create table),此时来自insert命令的数据将被提交到数据库。当DDL语句执行完成时,DDL语句会被自动提交,不能回滚。 

DML (Data Manipulation Language 数据操作语言)

insert 将记录插入到数据库 
update 修改数据库的记录 
delete 删除数据库的记录 
当执行DML命令如果没有提交,将不会被其他会话看到。除非在DML命令之后执行了DDL命令或DCL命令,或用户退出会话,或终止实例,此时系统会自动发出commit命令,使未提交的DML命令提交。

7.内连接、左外连接和右外连接的区别?


8.数据库的三大范式?


9.防止sql注入的方法?

1.把应用服务器的数据库权限降至最低

2.(简单又有效的方法)PreparedStatement

采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
​
使用好处:
​
(1).代码的可读性和可维护性.
​
(2).PreparedStatement尽最大可能提高性能.
​
(3).最重要的一点是极大地提高了安全性.
​
原理:
​
sql注入只对sql语句的准备(编译)过程有破坏作用
​
而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,
​
而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.

3.使用正则表达式过滤传入的参数

4.字符串过滤

5.对进入数据库的特殊字符进行转义处理

6.JSP页面判断代码

7.使用专门的SQL 注入检测工具测试,如sqlmap、SQLninja等

 

spring面试题

1.你对spring的理解?与springmvc和springboot的区别?(经常被问到)

Spring 是个Java企业级应用的开源开发框架。

Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。

Spring 框架目标是简化Java企业级应用开发,它使得开发者只需要关心业务需求。

spring与springmvc的区别:

Spring是IOC和AOP的容器框架,SpringMVC是基于Spring功能之上添加的Web框架,想用SpringMVC必须先依赖Spring

spring与springboot的区别:

Spring boot是一个在Spring 的基础上搭建的全新的微框架,其目的是简化Spring的搭建和开发过程。

用最简练的语言概括就是:

Spring 是一个“引擎”

Spring MVC 是基于Spring的一个 MVC 框架 ;

Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。


2.spring 的优缺点

Spring 的核心概念是IOC和AOP,这两个核心服务的对象算是bean(POJO),定位是一个轻量级的框架

它具备以下优点:

spring中避免了关键字new造成的耦合问题;

spring本身就是一个工厂,不需要再编写工厂类了;

spring不需要进行明确的引用关系的传递,直接通过配置完成;

所有框架几乎都可以在spring中整合在一起使用;

spring编程=factory设计模式+proxy设计模式

当然,它的缺点也是不少的:

spring基于大量的xml 配置文件,使得我们花了大量的时间放在配置上,拖慢了开发的进度,springboot 问世后,提倡代码优于配置解决了这个问题。

spring 的内容太庞大,随便打断点查看的时候会出现十几二十层代码,阅览性不强,在实际开发的过程中spring的角色更像是胶水一样,充当整合各种技术的角色,同时作为bean的容器。

3.spring的核心技术(IOC、DI、AOP)


4.Bean的作用域

每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态,而singleton全局只有一个对象。

在一次Http请求中,容器会返回该Bean的同一实例。而对不同的Http请求则会产生新的Bean,而且该bean仅在当前Http Request内有效。

在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效。

在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。


5.Bean的生命周期

Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

  1. 实例化一个Bean--也就是我们常说的new;

  2. 按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;

  3. 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值

  4. 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);

  5. 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);

  6. 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;

  7. 如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。

  8. 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;

    注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。

  9. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法

  10. 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

 

以上10步骤可以作为面试或者笔试的模板,另外我们这里描述的是应用Spring上下文Bean的生命周期,如果应用Spring的工厂也就是BeanFactory的话去掉第5步就Ok了。


6.Spring 支持的事务管理类型


 

 

springmvc面试题

1.什么是Spring MVC ?简单介绍下你对springMVC的理解?

Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。


2.SpringMVC的流程?


3.Springmvc的优点


4.Spring MVC的主要组件?

  1. 前端控制器 DispatcherServlet(不需要程序员开发)

    作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。

  2. 处理器映射器HandlerMapping(不需要程序员开发)

    作用:根据请求的URL来查找Handler

  3. 处理器适配器HandlerAdapter

    注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。

  4. 处理器Handler(需要程序员开发)

  5. 视图解析器 ViewResolver(不需要程序员开发)

    作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)

  6. 视图View(需要程序员开发jsp)

    View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)


6.SpringMVC怎么样设定重定向和转发的?


7.GET和POST区别?

注解配置:@RequestMapping注解里面加上method=RequestMethod.GET

  • url可见性

    get,参数url可见;

    post,url参数不可见

  • 数据传输上

    get,通过拼接url进行传递参数;

    post,通过body体传输参数

  • 缓存性

    get请求是可以缓存的

    post请求不可以缓存

  • 后退页面的反应

    get请求页面后退时,不产生影响

    post请求页面后退时,会重新提交请求

  • 传输数据的大小

    get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)

    post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大

  • 安全性

    这个也是最不好分析的,原则上post肯定要比get安全,毕竟传输参数时url不可见,但也挡不住部分人闲的没事在那抓包玩。安全性个人觉得是没多大区别的,防君子不防小人就是这个道理。对传递的参数进行加密,其实都一样。


8.cookie和session的区别?


9.spring mvc中的mvc指的是什么?

10.spring MVC中拦截器与过滤器的用处?加载顺序?

 

 

 

springboot面试题

1.为什么要用springboot?

能够简化搭建Spring项目的过程,省去了繁杂的配置过程,对开发者更友好


2.Spring Boot有哪些优点?


3.Spring Boot有哪些核心配置文件

  1. bootstrap(.yml或者.properties):bootstrap是应用程序的父上下文,拥有更高的加载优先级,主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。

  2. application(.yml或者.properties):主要用于Sprint Boot项目的自动化配置。


4.Spring Boot 的配置文件有哪几种格式

.properties和.yml两种格式,主要的区别在于书写方式不同

(1) .properties

app.user.name = javastack

(2) .yml

app:
user:
  name: javastack

5.Spring Boot 实现热部署有哪几种方式

主要有两种方式:


6.运行SpringBoot有几种方式?


7.springboot四大特性

  1. Starter添加项目依赖

  2. bean的自动化配置

  3. Spring Boot CLI与Groovy的高效配合

    Spring Boot CLI充分利用了Spring Boot Starter和自动配置的魔力,并添加了一些Groovy的功能。它简化了Spring的开发流程,通过CLI,我们能够运行一个或多个Groovy脚本,并查看它是如何运行的。在应用的运行过程中,CLI能够自动导入Spring类型并解析依赖

  4. Spring Boot Actuator

    完成的主要功能就是为基于Spring Boot的应用添加多个有用的管理端点


8.什么是Swagger?你用Spring Boot实现了吗?

Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱。Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现。它使文档能够以与服务器相同的速度更新。当通过 Swagger 正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger消除了调用服务时的猜测。


9.什么是FreeMarker模板?

FreeMarker 是一个基于 Java 的模板引擎,最初专注于使用 MVC 软件架构进行动态网页生成。使用 Freemarker 的主要优点是表示层和业务层的完全分离。程序员可以处理应用程序代码,而设计人员可以处理 html 页面设计。最后使用freemarker 可以将这些结合起来,给出最终的输出页面。


10.springboot常用注解?

  1. 启动注解 @SpringBootApplication

    查看源码可发现,@SpringBootApplication是一个复合注解,包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan这三个注解

  2. @Controller和@Restcontroller

    @Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。

    @Restcontroller用来将json/xml数据发送到前台页面,而不是返回视图页面。

    区别:

    • @RestController加在类上面的注解,使得类里面的每个方法都将json/xml返回数据加返回到前台页面中。

    • @Controller加在类上面的注解,使得类里面的每个方法都返回一个试图页面。

    • @Controller和@ResponseBody(加在方法/类上面)一起使用,和@RestController的作用相同。

  3. @RequestMapping

    @RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

  4. @Resource和@Autowired

    @Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。

    区别:

    • @Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配

    • @Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了

    • Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。

  5. @PathVariable

    用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。

  6. @RequestParam

    @RequestParam用于将请求参数区数据映射到功能处理方法的参数上

  7. @SessionAttributes

    @SessionAttributes即将值放到session作用域中,写在class上面。  

    @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(value 属性值),

    还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(types 属性值)

  8. @ResponseBody 

    该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

  9.  

 

 

 

mybatis面试题

1.MyBatis 的好处是什么,为什么用mybatis等?(多次被问到)


2.mybatis与hibernate的区别在哪里?(多次被问到)


3.#{}和${}的区别是什么?

${} 是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdbc.Driver;

#{}是sql的参数占位符,Mybatis会将sql中的#{}替换为?号,在sql执行前会使用PreparedStatement的参数设置方法,按序给sql的?号占位符设置参数值,比如ps.setInt(0, parameterValue),#{item.name}的取值方式为使用反射从参数对象中获取item对象的name属性值,相当于param.getItem().getName()。

不同点

#{}是预编译处理,${}是字符串替换。

Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值,可以有效的防止SQL注入,提高系统安全性;

在处理${}时,就是把${}替换成变量的值,一般用于传入数据库对象,例如传入表名。

用法:

select * from user where name = #{name}; 
select * from user where name = '${name}'; //必须加单引号

4.Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中<sql>为sql片段标签,通过<include>标签引入sql片段,<selectKey>为不支持自增的主键生成策略标签。

bind 元素标签可以从 OGNL 表达式中创建一个变量井将其绑定到上下文中,MyBatis中使用mysql的模糊查询字符串拼接(like) 中也涉及到bind的使用。创建一个 bind 元素标签的变量后 ,就可以在下面直接使用,使用 bind 拼接字符串不仅可以避免因更换数据库而修改 SQL,也能预防 SQL 注入。

<select id="getEmpsTestInnerParameter" resultType="com.hand.mybatis.bean.Employee">
       <!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
       <bind name="bindeName" value="'%'+eName+'%'"/> eName是employee中一个属性值
       SELECT * FROM emp 
       <if test="_parameter!=null">
         where ename like #{bindeName}
       </if>
   </select>

5.Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10

mybatis的两种分页方式:RowBounds和PageHelper


6.Mybatis执行批量插入,能返回数据库主键列表吗?

能,JDBC都能,Mybatis当然也能。

  1. 对于支持生成自增主键的数据库:增加 useGenerateKeys和keyProperty ,<insert>标签属性。

  2. 不支持生成自增主键的数据库:使用<selectKey>。


7.mybatis传递参数的方式(4种)?


8.mybatis中模糊查询(mysql)

<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
 select * from student where name like "%" #{name} "%"
</select>

 

 

 

事务面试题

1.事务的7种传播级别

1) PROPAGATION_REQUIRED ,默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。

2)PROPAGATION_SUPPORTS ,从字面意思就知道,supports,支持,该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。

3)PROPAGATION_MANDATORY , 该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。

4)PROPAGATION_REQUIRES_NEW ,从字面即可知道,new,每次都要一个新事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。

这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。 怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。

5)PROPAGATION_NOT_SUPPORTED ,这个也可以从字面得知,not supported ,不支持,当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。

这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用场了。用当前级别的事务模板抱起来就可以了。

6)PROPAGATION_NEVER ,该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!这个级别上辈子跟事务有仇。

7)PROPAGATION_NESTED ,字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。


2.数据隔离级别



3.Java有几种类型的事务?

Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。

 

设计模式

1.设计模式分类

常见的设计模式:

单例模式、工厂模式、建造模式、观察者模式、适配器模式、代理模式、装饰模式.


2.设计模式的优点


3.设计模式的六大原则及其含义

  1. 单一职责原则:一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。主要作用实现代码高内聚,低耦合。

  2. 开闭原则:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

  3. 里氏替换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。里氏替换原则是实现开闭原则的方式之一

  4. 依赖倒置原则:抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

  5. 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

  6. 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用。


4.常见的单例模式以及各种实现方式的优缺点,哪一种最好,手写常见的单例模式

饿汉式

懒汉式

双重检测锁式Double Check Lock--DCL):


5.设计模式在实际场景的应用(待补充)

单例:连接数据库,记录日志


6.Spring中用到了哪些设计模式

  1. 工厂模式:spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。

  2. 代理模式:Spring的AOP就是代理模式的体现。

  3. 单例模式:比如在创建bean的时候。

  4. 策略模式:spring在实例化对象的时候使用到了。

  5. 工厂方法:Spring中的FactoryBean就是典型的工厂方法模式。

  6. 观察者模式:常用的地方是Listener的实现,spring中ApplicationListener就是观察者的体现。


7.MyBatis中用到了哪些设计模式

  1. Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;

  2. 工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;

  3. 单例模式,例如ErrorContext和LogFactory;

  4. 代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;

  5. 组合模式,例如SqlNode和各个子类ChooseSqlNode等;

  6. 模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;

  7. 适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;

  8. 装饰者模式,例如Cache包中的cache.decorators子包中等各个装饰者的实现;

  9. 迭代器模式,例如迭代器模式PropertyTokenizer;


8.动态代理

cglib,jdk

 

消息队列

1.为什么使用消息队列?(解耦、异步、削峰)

主要解决应用耦合,异步消息,流量削锋等问题。

可实现高性能,高可用,可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。


2.使用了消息队列会有什么缺点


3.消息队列如何选型?

特性ActiveMQRabbitMQRocketMQkafka
开发语言javaerlangjavascala
单机吞吐量万级万级10万级10万级
时效性ms级us级ms级ms级以内
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)
功能特性成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好基于erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富MQ功能比较完备,扩展性佳只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。

4.消息队列由哪些角色组成?

拉取(Pull),是指 Consumer 主动从 Message Broker 获取消息

推送(Push),是指 Message Broker 主动将 Consumer 感兴趣的消息推送给 Consumer 。


5.消息队列有哪些使用场景?

一般来说,有下面使用场景:

其中,应用解耦、异步处理是比较核心的

 

数据结构

1.排序算法有哪些?

插入排序,冒泡排序,选择排序,快速排序,堆排序,归并排序,基数排序,希尔排序等。


2.以下算法的时间复杂度

冒泡排序法 O(n^2)

插入排序法 O(n^2)

堆排序法 O(nlog2 n)

二叉树排序法 最差O(n2)平均O(n*log2n)

快速排序法 最差O(n2)平均O(n*log2n)

希尔排序法 O(nlog n) 不稳定


3.数组和链表的区别


4.解决哈希冲突的方法

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。

 

 

JVM面试题

1.内存模型以及分区,需要详细到每个区放什么。


2.简述 java 垃圾回收机制?

在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚

拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。


3.java 类加载过程?

加载时类加载的第一个过程,在这个阶段,将完成一下三件事情:

  1. 通过一个类的全限定名获取该类的二进制流。

  2. 将该二进制流中的静态存储结构转化为方法去运行时数据结构。

  3. 在内存中生成该类的 Class 对象,作为该类的数据访问入口。

验证的目的是为了确保 Class 文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成

以下四钟验证:

  1. 文件格式验证:验证字节流是否符合 Class 文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.

  2. 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。

  3. 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。

  4. 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。

准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进

行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象

一起分配在 Java 堆中。

public static int value=123;*//在准备阶段 value 初始值为 0 。在初始化阶段才会变 *

为 123

该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。

初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。

到了初始化阶段,才真正开始执行类中定义的 Java 程序代码。

 

 

 

servlet面试题

1.Servlet的生命周期?

加载和实例化、初始化、处理请求以及服务结束

Servlet被服务器实例化后,容器运行其init方法,

请求到达时运行其service方法,

service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,

当服务器决定将实例销毁的时候调用其destroy方法


2.forward() 与redirect()的区别

forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,其实客户端浏览器只发了一次请求,所以它的地址栏中还是原来的地址,session,request参数都可以获取。

redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,相当于客户端浏览器发送了两次请求。


3.四种会话跟踪技术

1)page否是代表与一个页面相关的对象和属性。一个页面由一个编译好的 Java servlet 类(可以带有任何的 include 指令,但是没有 include 动作)表示。这既包括 servlet 又包括被编译成 servlet 的 JSP 页面

2)request是是代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件(由于 forward 指令和 include 动作的关系)

3)session是是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性。一个 Web 会话可以也经常会跨越多个客户机请求

4)application是是代表与整个 Web 应用程序相关的对象和属性。这实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域


4.Request对象的主要方法

5.Servlet执行时一般实现哪几个方法?

6.GenericServlet和HttpServlet有什么区别?

7.九大内置对象

 

Linux常用命令(被问到比较少)

用户操作命令(比较常用):

查看进程ps命令:

一般项目中,我们首先要查询一个进程,并对其进行删除会用一下命令

ps -a | grep helloworld 或 ps -ef |grep helloworld 或者 其他

查询到helloworld相关的进程,我们通过kill命令来操作该进程号删除该进程,kill -9 13492

显示目录和文件的命令:

修改目录,文件权限和属主及数组命令:

创建和删除目录的命令:

创建和删除,重命名,复制文件的命令:

显示文件内容的命令:

查找命令:

关机和重启计算机的命令:

 -k 并不真正的关机,而只是发出警告信息给所有用户
​ -h 关机后不重新启动

    0级用于关闭系统
    1级用于单一使用者模式
    2级用来进行多用户使用模式(但不带网络功能)
    3级用来进行多用户使用模式(带网络全功能)
    4级用来进行用户自定义使用模式
    5级表示进入x  windows时的模式
    6级用来重启系统

压缩和打包命令(比较常用):

文件连接命令:

可以分为软连接和硬链接:

软连接:也称为符号连接,即为文件或目录创建一个快捷方式。

硬链接:给一个文件取多于一个名字,放在不同目录中,方便用户使用。

Ln命令参数如下:

其他命令

     -ami  显示当前用户

    -u:显示使用者的动作/工作

    -s:使用简短的格式来显示

    -v:显示程序版本

vi编辑器

首先用vi命令打开一个文件

末行模式命令:

网络通信常用的命令

 

 

 

 

 

标签:面试题,return,String,2021.05,Spring,更新,线程,使用,方法
来源: https://blog.csdn.net/tj1996/article/details/116659368