Java面试大全(2020年版)1-100

目录

1. ArrayList和LinkedList的区别是什么(面试)?

  • 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
  • 底层数据结构: Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向循环链表数据结构;
  • 插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。
  • 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而ArrayList 实现了RandmoAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  • 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。

2. 什么是List接口

  • 是元素有序并且可以重复的集合,被称为序列,
  • List可以精准的控制每个元素的插入位置,或者删除某个位置元素
  • List接口的常用子类有ArrayList,LinkedList,Vector(已经过时)

3. 什么是HashMap(重点)

  • HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key
  • 本质为无序散列,Hash算法来决定存储位置.
  • HashMap的数据结构和底层实现(面试重点),JDk1.8之前的HashMap由数组+链表组成的,即”链表散列”,数组是HashMap的主题,链表则是主要是为了解决哈希冲突而存在的(“拉链法”),如果定位到的数组位置不含链表(entry的next指向null),那么对于查找,添加等操作很快,仅需要一次就能寻找到地址;如果定位到数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,急需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一对比.
  • HashMap不是线程安全的,当迭代其中有其他的线程改变了HashMap中的值将会抛出ConcurrentModifcationException.

4. 关于HashMap的扩容机制

Threshold(开始扩容的临界点)=Size(HashMap的容量)*Load_Factor(负载因子);

5. 什么时候开始扩容?

当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过160.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置。
为什么是0.75,大量实验得出的结果
如果取0.5,超过一般就扩容,造成资源的浪费.
如果取1,到临界值才扩容,会增加哈希碰撞的机率.

6. 扩容的方法是?

调用resize方法

7. Hashmap为什么大小是2的幂次?

为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。

8. HashMap线程安全问题,对应的线程安全Map是什么?

  • 对应的的是ConCurrentHashMap支持高并发的访问和更新,它是线程安全的.
  • ConCurrentHashMap在JDK1.8中和HashMap的底层相同都是散列表+红黑树
  • 通过部分锁定+CAs算法来进行实现线程安全的.
  • ConCurrentHashMap的key和Value都不能为null。

9. 什么是CAs算法?

Compare and swap是一种有名的无锁算法,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其他线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试.
总结:先比较是否相等,如果相当则替换。

10. 什么是进程?

是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。

11. 什么是线程?

进程内部的一个独立执行单元;一个进程可以同时并发的运行多个线程,可以理解为一个进程便相当于一个单 CPU 操作系统,而线程便是这个系统中运行的多个任务。

12. 什么是并发?

指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上有多个进程同时执行的效果。

13. 什么是并行?

指在同一时刻,有多条指令在多个处理器上同时执行。

14. 多线程有什么优势?

  • 进程之间不能共享内存,但线程之间共享内存非常容易。
  • 系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高
  • Java语言内置了多线程功能支持,从而简化了Java的多线程编程

15. Thread和Runnable的区别

实现Runnable接口比继承Thread类所具有的优势:

  • 适合多个相同的程序代码的线程去处理同一个资源
  • 可以避免java中的单继承的限制
  • 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
  • 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

16. 多线程的生命周期

在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)五种状态。
流程:
1)、新建状态(New):新创建了一个线程对象。
2)、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3)、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4)、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
5)、死亡状态(Dead):线程会以一下三种方式结束:
①run()或call()方法执行完成,线程正常结束
②线程抛出一个未捕获的Exception或Error
③直接调用该线程的stop()方法来结束线程——该方法容易导致死锁
注:当主线程结束时,其他线程不受影响,不会随之结束。
线程睡眠:Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
线程等待:Object类中的wait()方法(无限等待),导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0) 一样。
线程让步:Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
线程加入:join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
线程唤醒:Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。

17. 什么是线程安全和线程不安全?

由于系统的线程调度具有一定的随机性,当使用多个线程来访问同一个数据时,很容易“偶然“出现线程安全问题。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

18. 什么叫线程安全?

就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问,直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。

19. 何为线程不安全

线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

20. 线程同步锁有什么特点?

同步代码块:synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
synchronized(obj){需要同步的代码(多条语句操作共享数据的代码)}
obj:同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

  1. 锁对象可以是任意类型。
  2. 多个线程对象要使用同一把锁。

21. 同步有什么特点:

同步的前提是:多个线程并且多个线程使用的是同一个锁对象

22. 同步的有什么好处

同步的出现解决了多线程的安全问题

23. 同步有什么弊端

当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

24. 同步方法:

同步方法就是使用synchronized关键字来修饰某个方法,则该方法称为同步方法。同步方法的同步监视器是this,也就是调用该方法的对象。

25. 同步锁是谁?

对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。

26. 线程安全的类具有什么特征

  • 该类的对象可以被多个线程安全的访问
  • 每个线程调用该对象的任意方法之后都将得到正确结果
  • 每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。

27. Java中sleep方法和wait方法的区别?

虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿,因为它不会释放锁,而 wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁

28. run()方法和start()方法区别:

run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。启动线程使用start()方法,不是run()方法。调用start()方法来启动线程,系统会把该线程run()方法当成线程执行体来处理。如果直接调用run()方法,则run()方法会被当成普通方法立即执行,而不是线程执行体。而且在run()方法返回之前其他线程无法并发执行。

29. 多线程有几种实现方法?同步有几种实现方法?

①多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
②同步的实现方面有两种,分别是synchronized,wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉
InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某
一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

30. 启动一个线程是用run()还是start()?

启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。

31. 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

分几种情况
1).其他方法前是否加了synchronized关键字,如果没加,则能。
2).如果这个方法内部调用了wait,则可以进入其他synchronized方法。
3).如果其他个方法都加了synchronized关键字,并且内部没有调用wait,则不能。
4).如果其他方法是static,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是this。

32. 线程的基本概念、线程的基本状态以及状态之间的关系

①一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即main方法执行的那个线程。(如果只是一个cpu,它怎么能够同时执行多段程序呢?这是从宏观上来看的,cpu一会执行a线索,一会执行b线索,切换时间很快,给人的感觉是a,b在同时执行,好比大家在同一个办公室上网,只有一条链接到外部网线,其实,这条网线一会为a传数据,一会为b传数据,由于切换时间很短暂,所以,大家感觉都在同时上网。)
②线程基本状态:就绪,运行,synchronize阻塞,wait和sleep挂起,结束。wait必须在synchronized内部调用。调用线程的start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到synchronized语句时,由运行状态转为阻塞,当synchronized获得锁后,由阻塞转为运行,在这种情况可以调用wait方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态。

33. 简述synchronized和java.util.concurrent.locks.Lock的异同?

主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。

34. java中有几种类型的流?

字符流和字节流。字节流继承inputStream和OutputStream,字符流继承自InputSteamReader和OutputStreamWriter。

35. 谈谈Java IO里面的常见类,字节流,字符流、接口、实现类、方法阻塞

输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。
IO流主要分为字符流和字节流。
①字符流中有抽象类InputStream和OutputStream,它们的子类FileInputStream,FileOutputStream,BufferedOutputStream等。
②字符流BufferedReader和Writer等。都实现了Closeable, Flushable,
③Appendable这些接口。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
④java中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,否则程序会一直停留在该语句上,不会执行下面的语句。比如read()和readLine()方法。

36. 字符流和字节流有什么区别?

字符流以字符或者字符数组的形式读写数据,只能读写二进制文件;字节流能读写各种类型的数据。
字节流与字符流的不同是他们的处理方式,字节流是最基本的,采用ASCII编码。
但是实际上很多数据是文本,所以提出字符流的概念,采用unicode编码
两者之间通过inputStreamReader与outputStreamWriter来关联,实际上是通过byte[]与String来关联
字节流输出: 程序–>字节流–>文件
字符流输出:程序–>字符流–>缓冲–>文件
程序中所有的数据都是以流的方式进行传输与保存的
在关闭字符流后会强制性的将缓冲区的数据输出,若没有关闭缓冲区的内容是无法输出的,
如果想不关闭并且还想输出缓冲区的内容,用writer类的flush()方法来完成,

37. 讲讲NIO

看了一些文章,传统的IO流是阻塞式的,会一直监听一个ServerSocket,在调用read等方法时,他会一直等到数据到来或者缓冲区已满时才返回。调用accept也是一直阻塞到有客户端连接才会返回。每个客户端连接过来后,服务端都会启动一个线程去处理该客户端的请求。并且多线程处理多个连接。每个线程拥有自己的栈空间并且占用一些 CPU 时间。每个线程遇到外部未准备好的时候,都会阻塞掉。阻塞的结果就是会带来大量的进程上下文切换。
对于NIO,它是非阻塞式,核心类:
1.Buffer为所有的原始类型提供 (Buffer)缓存支持。
2.Charset字符集编码解码解决方案
3.Channel一个新的原始I/O抽象,用于读写Buffer类型,通道可以认为是一种连接,可以是到特定设备,程序或者是网络的连接。

38. BufferedReader属于哪种流,它主要是用来做什么的,它里面有那些经典的方法

属于处理流中的缓冲流,可以将读取的内容存在内存里面,有readLine()方法

39. 什么是节点流,什么是处理流,它们各有什么用处,处理流的创建有什么特征

节点流直接与数据源相连,用于输入或者输出处理流:在节点流的基础上对之进行加工,进行一些功能的扩展处理流的构造器必须要 传入节点流的子类

40. 如果我要对字节流进行大量的从硬盘读取,要用那个流,为什么

BufferedInputStream使用缓冲流能够减少对硬盘的损伤

41. 如果我要打印出不同类型的数据到数据源,那么最适合的流是那个流,为什么

Printwriter可以打印各种数据类型

42. 怎么样把我们控制台的输出改成输出到一个文件里面,这个技术叫什么

SetOut(printWriter,printStream)重定向

43. 怎么样把输出字节流转换成输出字符流,说出它的步骤

使用转换处理流OutputStreamWriter 可以将字节流转为字符流New OutputStreamWriter(new FileOutputStream(File file));

44. 什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作

对象序列化:将对象以二进制的形式保存到硬盘上;
反序列化:将二进制文件转化为对象读取.
将需要序化的类实现Serializable接口

45. 解释一下java.io.Serializable接口

类通过实现 Java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
①PrintStream、BufferedWriter、PrintWriter的比较?
PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。
②与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志,另外,为了自动刷新,可以创建一个 PrintStream
③BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用BufferedInputStream。
④PrintWriter的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush);

46. 什么是节点流,什么是处理流,它们各有什么用处,处理流的创建有什么特征

节点流 直接与数据源相连,用于输入或者输出
处理流:在节点流的基础上对之进行加工,进行一些功能的扩展处理流的构造器必须要 传入节点流的子类

47. InputStream里的read()返回的是什么,read(byte[] data)是什么意思,返回的是什么值

返回的是所读取的字节的int型(范围0-255)read(byte [ ] data),将读取的字节储存在这个数组,返回的就是传入数组参数个数Read字节读取字节、字符读取字符

48. OutputStream里面的write()是什么意思,write(byte b[], int off, int len)这个方法里面的三个参数分别是什么意思

write将指定字节传入数据源
Byte b[ ]是byte数组
b[off]是传入的第一个字符
b[off+len-1]是传入的最后的一个字符
len是实际长度

49. 什么是sql语句优化?

就是对性能低下的sql语句转化成目的相同但是性能优异的语句。

50. sql优化的几种方法

  • 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

  • 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
    select id from t where num is null
    可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
    select id from t where num=0

  • 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

  • 应尽量避免在 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

  • 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

  • 下面的查询也将导致全表扫描:
    select id from t where name like ‘%abc%’

  • 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where num/2=100
    应改为:
    select id from t where num=100*2

  • 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where substring(name,1,3)=‘abc’–name以abc开头的id
    应改为:
    select id from t where name like ‘abc%’

  • 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

  • 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

  • 不要写一些没有意义的查询,如需要生成一个空表结构:
    select col1,col2 into #t from t where 1=0
    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
    create table #t(…)

  • 很多时候用 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)

  • 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

  • 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
    一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

  • 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

  • 尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

  • 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

  • 避免频繁创建和删除临时表,以减少系统表资源的消耗。

  • 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

  • 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

  • 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

  • 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

  • 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。

51. 为何要进行sql优化

因为sql语句是对数据库进行操作的惟一途径,对数据库系统的性能起着决定性的作用,所以优化它,能够提高访问速度。

52. 如何找出需要优化的sql语句呢?

  • 开启慢查询日志 :当一条sql执行超时时,mysql可以将慢的sql记录到日志中。
  • 使用执行计划(explain)分析慢的原因:执行计划能将 sql语句发送给mysql评估执行该条sql需要经历哪些步骤消耗多少资源
  • show profile: 主要是用来查询SQL在mysql服务器里面的执行细节和生命周期情况
  • 数据库服务器参数性能调优

53. 数据库的表结构优化

  • 在创建表的属性时,要选择最合适的字段
    Mysql是一种关系型数据库,可以很好地支 持大数据量的存储,但是一般来说,数据库中的表越小,在它上面执行的查询也就越快。因此,在创建表的时候,为了获得更好的性能。
  • 尽量把字段设置为NOT NULL
    在可能的情况下,尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库不用去比较NULL值。
  • 创建索引
    • 索引是对数据库表中一个或多个列的值进行排序的结构.使用索引查询可以避免全表扫描。
    • 创建索引的语句: create index 创建名 on 表名字(字段名)。
    • 如果想查看当前表是否需要优化可以查看数据库中查询效率:

54. 数据库的存储引擎

MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。
查看数据库的存储引擎:SHOW VARIABLES LIKE ‘storage_engine’
常见的三种存储引擎

  • InnoDB存储引擎
  • MyISAM存储引擎
  • MEMORY存储引擎

55. 常用函数:

  • 数学函数:数学函数主要用于处理数字,包括整型、浮点数等。
  • 字符串函数:字符串函数是MySQL中最常用的一类函数,字符串函数主要用于处理表中的字符串。
  • 日期时间函数:MySQL的日期和时间函数主要用于处理日期时间。
  • 系统信息函数:系统信息函数用来查询MySQL数据库的系统信息。
  • 加密函数:加密函数是MySQL用来对数据进行加密的函数。

56. 数据库三范式是什么?

  • 第一范式(1NF):字段具有原子性,不可再分。所有关系型数据库系统都满足第一范式)
  • 第二范式(2NF):第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
    (要求数据库表中的每个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。)
  • 第三范式的要求:满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
    所以第三范式具有如下特征:
    1).每一列只有一个值
    2).每一行都能区分。
    3).每一个表都不包含其他表已经包含的非主关键字信息。

57. 说出一些数据库优化方面的经验?

用PreparedStatement 一般来说比Statement性能高:一个sql 发给服务器去执行,涉及步骤:
语法检查、语义分析, 编译,缓存有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数据库时就去掉外键。(比喻:就好比免检产品,就是为了提高效率,充分相信产品的制造商)表中允许适当冗余;sql语句全部大写,特别是列名和表名都大写。

58. Dubbo是什么?

DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC(远程过程调用协议)远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架。
说白了就是个远程服务调用的分布式框架。其核心部分包含:

  • 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
  • 集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
  • 自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

59. 为什么要用Dubbo(优点和好处),解决什么问题?

Dubbo提供了三个关键功能:基于接口的远程调用,容错与负载均衡,服务自动注册与发现。

  • 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
  • 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
  • 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

60. Dubbo如何暴露与发现服务?(一定要懂)

节点角色说明:

  • Provider: 暴露服务的服务提供方。
  • Consumer: 调用远程服务的服务消费方。
  • Registry: 服务注册与发现的注册中心。
  • Monitor: 统计服务的调用次调和调用时间的监控中心。
  • Container: 服务运行容器。
    调用关系说明:
  • 服务容器负责启动,加载,运行服务提供者。
  • 服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者在启动时,向注册中心订阅自己所需的服务。
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推
    送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,
    如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计
    数据到监控中心。

61. Dubbo 和 Spring Cloud 有什么区别?

Dubbo 使用的是 RPC 通信,而 Spring Cloud 使用的是 HTTP RESTFul 方式。这两种方式各有优劣。对于类似于电商等同步调用场景多并且能支撑搭建Dubbo 这套比较复杂环境的成本的产品而言,Dubbo 确实是一个可以考虑的选择。虽然在一定程度上来说Spring Cloud牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更为合适。

62. Dubbo 支持的通信协议有哪些?

  • dubbo协议(默认),使用NIO异步通信,单一长连接,hessian序列化协议,使用在传输数据量较小(每次请求在100kb以内),但是并发量很高的场景。
  • rmi(Remote Method Invocation 远程方法调用)java二进制序列化,使用在多个短连接,使用在消费者和提供者数量差不多的情况,适用于文件的传输,一般比较少用。
  • hessian协议,hessian序列化协议,多个短连接,使用在提供者比消费者数量还多的请你赶快,适用于文件传输,一般比较少用。

63. 怎么实现远程通信

远程通信:简单来说,就是一个系统去调用另一个系统中的数据。
常见的有三种方式:

  • Webservice的方式:
    • 优点:跨语言跨平台
    • 缺点:它是基于soap协议的,使用http+xml的方式进行数据传输,http是应用层协议,传输效率不是很高,而且xml的解析也比 较费时,所以项目内部进行通信的时候,不建议使用Websservice的方式
  • restful形式的服务:
    • 优点:restful本身就是http,使用的是http+json的方式进行数据传输,因为json数据本身是非常简洁的,所以它比webservice的 传输效率更高;手机app端一般都使用该方法,其他很多项目也是用这种方式
    • 缺点:如果服务太多的话,会出现服务之间调用关系混乱,此时就需要治理服务
  • Dubbo:使用的是RPC协议进行远程调用,RPC协议是一个二进制协议,直接使用的socket进行通信,传输效率高,并且可以统计出系统 之间的调用关系和调用次数系统分布式SAO系统的内部通信推荐使用dubbo

64. Dubbo为什么使用异步单一长连接?

Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。

65. Dubbo有哪几种集群容错方案,默认是哪种?

  • Failover Cluster:失败重试
    当服务消费方调用服务提供者失败后自动切换到其他服务提供者服务器进行重试。这通常用于读操作或者具有幂等的写操作,需要注意的是重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。
  • Failfast Cluster:快速失败
    当服务消费方调用服务提供者失败后,立即报错,也就是只调用一次。通常这种模式用于非幂等性的写操作。
  • Failsafe Cluster:失败安全
    当服务消费者调用服务出现异常时,直接忽略异常。这种模式通常用于写入审计日志等操作。
  • Failback Cluster:失败自动恢复
    当服务消费端用服务出现异常后,在后台记录失败的请求,并按照一定的策略后期再进行重试。这种模式通常用于消息通知操作。
  • Forking Cluster:并行调用
    当消费方调用一个接口方法后,Dubbo Client会并行调用多个服务提供者的服务,只要一个成功即返回。这种模式通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
  • Broadcast Cluster:广播调用
    当消费者调用一个接口方法后,Dubbo Client会逐个调用所有服务提供者,任意一台调用异常则这次调用就标志失败。这种模式通常用于通知所有提供者更新缓存或日志等本地资源信息。
    如上,Dubbo本身提供了丰富的集群容错模式,但是如果您有定制化需求,可以根据Dubbo提供的扩展接口Cluster进行定制。

66. Dubbo的异常机制是什么?

Dubbo有一个名为ExceptionFilter的异常过滤器,包含如下机制:

  • 如果是checked异常,直接抛出!
  • 在方法签名上有声明,直接抛出 throws MyCustomException
  • 异常类和接口类在同一jar包里,直接抛出
  • 是JDK自带的异常,直接抛出(className.startsWith(“java.”) || className.startsWith(“javax.”))
  • 是Dubbo本身的异常,直接抛出(RpcException)
  • 其他异常通过RuntimeException

67. 挂机_Dubbo挂机了怎么处理

首先zookeeper挂了还能调用服务,在启动dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用。但是在注册中心全部挂掉后增加新的提供者,则不能被消费者发现.(前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的。

68. 安全_dubbo+zookeeper如何解决不同系统间调用的安全性问题

Dubbo通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。

  • 可以全局设置开启令牌验证:

<dubbo:provider interface=“com.foo.BarService” token=“true” />

<dubbo:provider interface=“com.foo.BarService” token=“123456” />

  • 也可在服务级别设置:

<dubbo:service interface=“com.foo.BarService” token=“true” />

<dubbo:service interface=“com.foo.BarService” token=“123456” />

  • 还可在协议级别设置:

<dubbo:protocol name=“dubbo” token=“true” />

<dubbo:protocol name=“dubbo” token=“123456” />

69. Zookeeper 介绍(谈谈你对zookeeper的了解)

官方推荐使用 zookeeper 注册中心。注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。
Zookeeper 是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为Dubbox 服务的注册中心,工业强度较高,可用于生产环境。

70. 作用_zookeeper注册中心的作用?端口是多少

  • 作用:Zookeeper注册中心的作用主要就是注册和发现服务的作用。类似于房产中介的作用,在系统中并不参与服务的调用及数据的传输。
  • 端口及作用
    • 2181:对cline端提供服务
    • 3888:选举leader使用
    • 2888:集群内机器通讯使用(Leader监听此端口)

71. zookeeper在项目中怎么用的

  • 作为dubbo的注册中心,暴露服务,然后消费方订阅服务用的
  • 作为solr集群的调配中心,达到负载均衡的效果

72. 缺陷_zookeeper存在什么缺陷

  • 本身不是为高可用性设计,master撑不住高流量容易导致系统crash;
  • zookeeper的选举过程速度很慢;
  • 难以避免数据的不一致;
  • zookeeper的性能是有限的

73. springmvc框架的工作流程

  • 方式一:
    • 用户向服务器发送请求,请求被 SpringMVC的前端控制器 DispatcherServlet截获。
    • DispatcherServlet对请求的 URL(统一资源定位符)进行解析,得到 URI(请求资源标识符),然后根据该 URI,调用 HandlerMapping获得该 Handler配置的所有相关的对象,包括 Handler对象以及 Handler对象对应的拦截器,这些对象都会被封装到一个 HandlerExecutionChain对象当中返回。
    • DispatcherServlet根据获得的 Handler,选择一个合适的 HandlerAdapter。HandlerAdapter的设计符合面向对象中的单一职责原则,代码结构清晰,便于维护,最为重要的是,代码的可复制性高。HandlerAdapter会被用于处理多种 Handler,调用 Handler实际处理请求的方法。
    • 提取请求中的模型数据,开始执行 Handler(Controller)。在填充 Handler的入参过程中,根据配置,spring将帮助做一些额外的工作
      消息转换:将请求的消息,如 json、xml等数据转换成一个对象,将对象转换为指定的响应信息。
      数据转换:对请求消息进行数据转换,如 String转换成 Integer、Double等。
      数据格式化:对请求的消息进行数据格式化,如将字符串转换为格式化数字或格式化日期等。
      数据验证:验证数据的有效性如长度、格式等,验证结果存储到 BindingResult或 Error中。
    • Handler执行完成后,向 DispatcherServlet返回一个 ModelAndView对象ModelAndView对象中应该包含视图名或视图模型。
    • 根据返回的ModelAndView对象,选择一个合适的 ViewResolver(视图解析器) 返回给
      DispatcherServlet。
    • ViewResolver结合 Model和 View来渲染视图。
    • 将视图渲染结果返回给客户端。
      以上 8个步骤,DispatcherServlet、HandlerMapping、HandlerAdapter和 ViewResolver等对象协同工
      作,完成 SpringMVC请求—>响应的整个工作流程,这些对象完成的工作对于开发者来说都是不可
      见的,开发者并不需要关心这些对象是如何工作的,开发者,只需要在 Handler(Controller)当中完成对请求的业务处理。
  • 方式二:
    • 用户发送请求至前端控制器DispatcherServlet;
    • DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
    • 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
    • DispatcherServlet 调用 HandlerAdapter处理器适配器;
    • HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
    • Handler执行完成返回ModelAndView;
    • HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
    • DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
    • ViewResolver解析后返回具体View;
    • DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
    • DispatcherServlet响应用户。

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

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

75. Springmvc有什么优点:

  • 可以支持各种视图技术,而不仅仅局限于JSP;
  • 与Spring框架集成(如IoC容器、AOP等);
  • 清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
  • 支持各种请求资源的映射策略。

76. Spring MVC的主要组件?

  • 前端控制器 DispatcherServlet(不需要程序员开发)
    作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
  • 处理器映射器HandlerMapping(不需要程序员开发)
    作用:根据请求的URL来查找Handler
  • 处理器适配器HandlerAdapter
    注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。
  • 处理器Handler(需要程序员开发)
  • 视图解析器 ViewResolver(不需要程序员开发)
    作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)
  • 视图View(需要程序员开发jsp)
    View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)

77. springMVC和struts2的区别有哪些?

  • springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。
  • springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
  • Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。

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

  • 转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"
  • 重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

79. SpringMvc怎么和AJAX相互调用的?

通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :

  • 加入Jackson.jar
  • 在配置文件中配置json的映射
  • 在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。

80. 如何解决POST请求中文乱码问题,GET的又如何处理呢?

  • 解决post请求乱码问题:
    在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;
  • get请求中文参数出现乱码解决方法有两个:
    • 修改tomcat配置文件添加编码与工程编码一致
    • 另外一种方法对参数进行重新编码:

81. Spring MVC的异常处理?

可以将异常抛给Spring框架,由Spring框架来处理;我们只需要配置简单的异常处理器,在异常处理器中添视图页面即可。

82. SpringMvc的控制器是不是单例模式,如果是,有什么问题,怎么解决?

是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。

83. SpringMVC常用的注解有哪些?

  • @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
  • @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
  • @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

84. SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代?

一般用@Conntroller注解,表示是表现层,不能用别的注解代替。

85. 如果在拦截请求中,我想拦截get方式提交的方法,怎么配置?

可以在@RequestMapping注解里面加上method=RequestMethod.GET。

86. 怎样在方法里面得到Request,或者Session?

直接在方法的形参中声明request,SpringMvc就自动把request对象传入。

87. 如果想在拦截的方法里面得到从前台传入的参数,怎么得到?

直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。

88. 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?

直接在方法中声明这个对象,SpringMvc就自动会把属性赋值到这个对象里面。

89. SpringMvc中函数的返回值是什么?

返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。

90. SpringMvc用什么对象从后台向前台传递数据的?

通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以通过el表达式拿到。

91. 怎么样把ModelMap里面的数据放入Session里面?

可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。

92. SpringMvc里面拦截器是怎么写的:

有两种写法:①一种是实现HandlerInterceptor接口;②另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可:

93. 注解原理:

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

94. 什么是Mybatis?

  • Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
  • MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • 通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。

95. Mybaits有什么优点:

  • 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
  • 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
  • 很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
  • 能够与Spring很好的集成;
  • 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

96. MyBatis框架的缺点:

  • SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
  • SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

97. MyBatis框架适用场合:

  • MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
  • 对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。

98. MyBatis与Hibernate有哪些不同?

  • Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
  • Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
  • Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。

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

#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理{}时,就是把{}替换成变量的值。使用#{}可以有效的防止SQL注入,提高系统安全性。

100. 当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

  • 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
  • 通过来映射字段名和实体类属性名的一一对应的关系。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章