java学习总结

基础部分

一、jdk与jre区别

JDK:它是Java开发运行环境,在程序员的电脑上当然要安装JDK;
JRE:Java Runtime Environment它是Java运行环境,如果你不需要开发只需要运行Java程序,那么你可以安装JRE

二、java跨平台的原理

java源程序(.java文件)通过编译器编译成为Class文件(字节码文件),而它的class文件是基于字节码(以byte为单位存储的文件)的,而字节码文件是描述程序要运行的的虚指令的集合,这些虚指令的集合与任何的平台无关,Java虚拟机认识它(只要在不同的平台下部署相应的jre,运行jvm!就可以了)

三、JVM

1.GC是什么?为什么要有GC?

GC是JVM中垃圾回收机制,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc()

2.如何判断对象可以被回收?

判断对象是否存活一般有两种方式:
引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。
可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,不可达对象。

3.引用的分类

强引用:GC时不会被回收
软引用:描述有用但不是必须的对象,在发生内存溢出异常之前被回收
弱引用:描述有用但不是必须的对象,在下一次GC时被回收
虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用PhantomReference实现虚引用,虚引用用来在GC时返回一个通知。

4.Java 中堆和栈有什么区别?

JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。

四、集合(重点)

1.Java中有哪些集合?

set(集)、list(列表)和map(映射)。
区别:List和Set继承了Collection接口,而map不是,List中存放元素有序并且可以重复;set中存放的元素是无序并且是不可能重复的,Map存储的时候将键值存入entry,然后存储entry对象。
在这里插入图片描述
在这里插入图片描述

2.Collection 和 Collections 有什么区别?

java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作

3.ArrayList和LinkedList的区别

ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。ArrayList采用数组实现的,查找效率比LinkedList高,LinkedList采用双向链表实现的,插入和删除的效率比ArrayList要高。

4.HashSet 的实现原理?

HashSet底层由HashMap实现,HashSet的值存放于HashMap的key上,HashMap的value统一为present。

5.HashMap的实现原理

HashMap 基于 Hash 算法实现的,我们通过put(key,value)存储,get(key)来获取。当传入key时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。当计算出的hash值相同时,我们称之为hash冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当hash冲突的个数比较少时,使用链表否则使用红黑树。
JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashCode 经过hash方法处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的 长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的 话,直接覆盖,不相同就通过拉链法解决冲突。
拉链法:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。

6.Hashtable理解

和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

7.Hashtable与HashMap的区别

Hashtable与HashMap都是用来存储key-value类型数据的,两者有如下区别:

  1. Hashtable不允许null key和null value,HashMap允许。
  2. Hashtable是线程安全的,HashMap不是线程安全的。
  3. HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
  4. Hashtable继承自Dictionary,HashMap继承自AbstractMap。
  5. 两者都实现了Map接口。

五、String

1.String的作用?

String是所有语言中最常用的一个类。String类在Java中被设计成final的,类不能被继承和修改。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。

2.String的原理?

String底层是一个不可变字符串,使用连接符的时候,实际上是经过了StringBuilder的优化处理的。并 不是在原来的String对象中做追加,而是使用了StringBuilder的 append()

3.String 和 StringBuilder、StringBuffer 的区别

Java 平台提供了两种类型的字符串:String 和 StringBuffer/StringBuilder,它 们可以储存和操作字符串。其中 String 是只读字符串,也就意味着 String 引用的 字符串内容是不能被改变的。而 StringBuffer/StringBuilder 类表示的字符串对象 可以直接进行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方 法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被 synchronized 修饰,因此它的效率也比 StringBuffer 要高。

4.String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
hashcode():返回字符串的哈希码值。

六、线程

1.线程是什么?

Thread类中有这样的明确定义:线程是程序中执行的线程,Java虚拟机允许程序同时运行多个执行线程。

2.线程有6种状态

新建,运行(可运行),阻塞,等待,计时等待和终止。
新建:当使用new操作符创建新线程时,线程处于“新建“状态
运行(可运行):调用start()方法
阻塞:当线程需要获得对象的内置锁,而该锁正在被其他线程拥有
等待:当线程等待其他线程通知调度表可以运行时
计时等待:对于一些含有时间参数的方法,如Thread类的sleep()
终止:当run()方法运行完毕或出现异常时

3.java 中有几种方法可以实现一个线程?

①. 创建一个实现Runnable接口的子类,子类重写run(),创建子类对象,然后将它作为参数传递给Thread的构造函数,创建一个Thread对象(就是创建线程)
②.创建一个继承Thread类的子类,子类重写run(),创建子类对象(其实就是创建线程)

4.什么是线程池? 为什么要使用它?

创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变 长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候 就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从 JDK1.5 开始,Java API 提供了 Executor 框架让你可以创建不同的线程池。
降低资源消耗
提高响应速度
提高线程的可管理性

5.如何让正在运行的线程暂停一段时间?

我们可以使用 Thread 类的 Sleep()方法让线程暂停一段时间。需要注意的是,这 并不会让线程终止,一旦从休眠中唤醒线程,线程的状态将会被改变为 Runnable, 并且根据线程调度,它将得到执行。

6.你对线程优先级的理解是什么?

每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权, 但这依赖于线程调度的实现,这个实现是和操作系统相关的(OS dependent)。我 们可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线 程前执行。线程优先级是一个 int 变量(从 1-10),1 代表最低优先级,10 代表最 高优先级。 java 的线程优先级调度会委托给操作系统去处理,所以与具体的操作系统优先级 有关,如非特别需要,一般无需设置线程优先级。

7.线程之间是如何通信的?

当线程间是可以共享资源时,线程间通信是协调它们的重要的手段。Object 类中 wait()\notify()\notifyAll()方法可以用于线程间通信关于资源的锁的状态。

8.如何确保线程安全?

在 Java 中可以有很多方法来保证线程安全——同步(synchronized),使用原子类(atomic concurrent classes),实现并发锁(Lock),使用 volatile 关键字,使用不变类和线程安 全类。

9.启动一个线程是调用 run()还是 start()方法?

启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态, 这意味着它可以由 JVM 调度并执行,这并不意味着线程就会立即运行。run()方 法是线程启动后要进行回调(callback)的方法。

10.sleep 方法和 wait 方法有什么区别?

sleep 方法和 wait 方法都可以用来放弃 CPU 一定的时间,不同点 在于如果线程持有某个对象的监视器,sleep 方法不会放弃这个对象的监视器, wait 方法会放弃这个对象的监视器

11.可以直接调用 Thread 类的 run ()方法么?

当然可以。但是如果我们调用了 Thread 的 run()方法,它的行为就会和普通的方 法一样,会在当前线程中执行。为了在新的线程中执行我们的代码,必须使用 Thread.start()方法。

七、反射

1.java反射机制的理解?反射机制是什么?

就是在程序运行期间,能够动态知道每个类的方法和属性,并且对于每一个对象都能够调用该对象的方法和属性。1.把javac编译过得字节码转换成二进制流文件 2.然后把二进制流文件加载到运行时数据区也就是方法区 3.在方法区中生成唯一一个代表该类的Class对象实例,作为访问该类的入口

web前端部分

一、MySQL

1.MySQL 中 四种事务隔离级别名称,以及逐 级之间的区别

MySQL默认隔离级别是读已提交。
SQL 标准定义的四个隔离级别为:

  1. read uncommited :读到未提交数据
  2. read committed:脏读,不可重复读
  3. repeatable read:可重读
  4. serializable :串行事物

2.数据库中的事务

事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有 操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所 有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作 失败,则事务将回滚,该事务所有操作的影响都将取消。
事务特性:

  1. 原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
  2. 一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状 态
  3. 隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何 其他事务,
  4. 持久性。事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后 有了其他故障,事务的处理结果也会得到保存。

3.MySQL的优化

  1. 慢日志查询
    MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志
  2. 缓存
    它既可以加快整个系统(并非数据库系统,使用缓存的时候并没有去访问数据库)的访问速度,也可以减少数据库负载的压力。而缓存一般都是在查询中使用,我们并不希望每一次的查询都要去访问数据库。那么我们的缓存做到哪里呢?一般情况下版的系统都会存在服务层这一结构层次,而数据访问层一般都只是对于数据库的增删改查的接口的定义,所以我们的缓存就需要在服务层进行。
  3. 当只需要一条数据时使用limit1
    我们作为开发者,是能够知道我们需要的数据的条数的,若已经知道结果只有一条的时候,一定要使用limit 1 ,这样一来,MySQL在查询到一条数据之后,会立即停止搜索,这会带来性能上的提升。
  4. 避免全表查询
    无论查询什么都是直接select ,然后再从结果中取想要的字段。这样做的话,平白无故的给MySQL带来了不必要的负担,因为从数据库中读出越多的数据,查询就会变得越慢。所以,以后看到select 的时候,想一下是否可以在这里进行一些优化。
  5. 为每张表设置一个id作为主键
    这个id最好是一个int类型的,推荐使用unsigned,并将其设置为自动增加auto_increment。将varchar的字段作为主键的情况, 然后在数据量较大的时候,数据库这个环节速度变得不是很友好,所以尽量不要使用varchar来当主键,它会使得性能出现下降。而且在某些情况下,id这个主键字段是非常重要的。
  6. 使用enum而不是varchar  
    实际上,enum保存的是tinyint类型,但其显示为字符串。用这个字段来作一些选项列表就变得很合适了。比如你有一个字段,比如“性别”、“状态”或“所属部门”等,你知道这些字段的值是固定且有限的,那么可以考虑使用enum。对于性别这个字段,一般分为两种,有可能还有保密这种情况,我们可以使用数字1、2、3来分别表示这三张情况,而对于这些数字含义的区分则是业务层的事情了。我们需要将一些繁琐的需要计算的步骤全部放到业务层(或者说是服务层),因为系统的瓶颈在数据库,我们不能将过多的计算过程压到数据库上面去。数据库存储的数据应该尽量简单,但是,我们会在业务层结合具体的业务,对这些简单的数据进行分析
  7. 尽可能的使用not null
    除非你有一个很特别的原因要去使用null值,你应该总让你的字段保持为not null。
  8. 选择正确的存储引擎
    myisam适合一些需要大量查询的应用。但其对于大量写操作并不是很好。因为它使用到的是表级锁,所以在你更新的时候,整张表都会被锁起来,试想一下,当你在更新某一行数据的时候,导致其他的行都无法被访问,这会不会 很难受呢。另外,myisam对于select count(*)这类操作的计算时很快的。而至于innodb而言,对于一些小的应用,它会比myisam还慢。它支持的是行级锁,于是写操作较多的时候,它会更加优秀。它还支持一些更高级的应用,比如说:事务。

4.SQL调优

  1. 创建必要的索引
    在经常需要进行检索的字段上创建索引,比如要按照姓名进行检索,那么就应该在姓名字段上创建索引,如果经常要按照员工部门和员工岗位级别进行检索,那么就应该在员工部门和员工岗位级别这两个字段上创建索引。创建索引给检索带来的性能提升往往是巨大的,因此在发现检索速度过慢的时候应该首先想到的就是创建索引。
  2. 使用预编译查询
    程序中通常是根据用户的输入来动态执行SQL,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞攻击,最重要数据库会对这些参数化SQL进行预编译,这样第一次执行的时候DBMS会为这个SQL语句进行查询优化并且执行预编译,这样以后再执行这个SQL的时候就直接使用预编译的结果,这样可以大大提高执行的速度。
  3. 调整Where字句中的连接顺序
    DBMS一般采用自下而上的顺序解析where字句,根据这个原理表连接最好写在其他where条件之前,那些可以过滤掉最大数量记录。
  4. 尽量将多条SQL语句压缩到一句SQL中
    每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程是非常耗时的,因此应该尽量避免过多的执行SQL语句,能够压缩到一句SQL执行的语句就不要用多条来执行。
  5. 用where字句替换HAVING字句
    避免使用HAVING字句,因为HAVING只会在检索出所有记录之后才对结果集进行过滤,而where则是在聚合前刷选记录,如果能通过where字句限制记录的数目,那就能减少这方面的开销。HAVING中的条件一般用于聚合函数的过滤,除此之外,应该将条件写在where字句中。
  6. 使用表的别名
    当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减少哪些友列名歧义引起的语法错误。
  7. 在in和exists中通常情况下使用EXISTS,因为in不走索引。
  8. 避免在索引上使用计算

5.SQL语句有哪些

查看:select * from 表名 where 范围
插入:insert into 表名(field1,field2) values值(value1,value2)
删除:delete from 表名 where 范围
更新:update 表名 set field1=value1 where 范围

二、前端页面(重点)

1.servlet生命周期

大概可以分为五个阶段,其中前三个阶段可以合成一个:

  1. 加载:从容器通过类加载器加载servlet
  2. 创建:通过构造函数创建实例化
  3. 初始化:用init()方法初始化servlet对象
  4. 处理客户请求:servletRequestservletResponse
  5. 回收:由JVM的垃圾回收器进行垃圾回收

2.描述Servlet调用过程

  1. 首先,客户端通过地址栏发送请求到服务器,
  2. 服务器通过查看http请求的Host确定浏览器访问的是哪一个虚拟主机,
  3. 根据请求行中的资源路径获知浏览器访问哪一个资源,
  4. 根据获取到的资源路径到web.xml中进行匹配,匹配真实的路径 由url-pattern->servlet-name->servlet-class
  5. 获取servlet实例,
  6. 服务器从request(响应对象)中获取要发送给浏览器的数据,按照Http协议规定的方式组织成响应信息,再发送给浏览器。

3.什么是http协议

HTTP协议就是一套基于tcp/ip协议的应用层协议 。简单来说,就是一个基于应用层的通信规范,双方要进行通信,大家都要遵守一个规范,这个规范就是HTTP协议。它规定了客户端(通常是浏览器)和服务器之间的通信方式。

4.HTTP协议工作原理

HTTP协议基于请求响应模型。一次请求对应一次响应。首先客户端发送一个请求(request)给服务器,服务器在接收到这个请求后将生成一个响应(response)返回给客户端。

5. Request生命周期

request对象的生命周期是针对一个客户端(一个浏览器应用程序)的一次请求,当请求完毕之后,request里边的内容也将被释放,一个请求开始时创建,请求结束后销毁。

6.转发与重定向的比较

转发是服务器内部资源跳转,重定向是通过302+Location实现浏览器跳转访问。转发一次请求一次响应,重定向两次请求两次响应。转发地址栏不发生变化,重定向地址栏会发生变化。转发之前和转发之后request是一个,重定向之前和之后不是一个request。

7.Session原理

session的原理:
在服务器第一次调用request.getSession()方法的时候,会在内存中创建一个session对象,此对象具有一个独一无二的id值,此id值将会以cookie(JSESSIONID)的形式发送给浏览器,浏览器以后每次访问都会带着此cookie,服务器就利用此cookie区分浏览器找到对应的session空间。

8.session的生命周期

当程序第一次调用到request.getSession()代码时,服务器明确的知道了需要用到session了,此时创建session。如果session超过30分钟(可以在web.xml中配置的)没人使用,服务器认为这个session超时了,销毁session。明确的调用session.invalidate(),session立即销毁。服务器被非正常关闭或web应用被移除出容器,此时随着web应用的销毁session销毁.如果是正常关闭,session会被钝化.当下次服务器正常启动时,没有超时的session还会被活化回来。

9.cookie与session的区别

cookie数据存放在客户的浏览器上,session数据放在服务器上cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用sessionsession会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie

框架部分

一、Spring

1.对spring框架的理解

Spring是一个轻量级的开源框架,能够简化企业级应用开发,减少代码量,核心框架是AOP与IOC。ioc也就是控制反转,将类的创建和依赖关系写在配置文件里面,使用依赖注入方式注入到相应的类里使用,将创建对象的权利交给工厂。Aop(面向切面编程)将程序重复的代码抽取出来,使用动态代理的技术,在不修改源码的基础上,对已有的方法进行增强,提高了复用性

2.SpringIOC的原理

所谓ioc,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。ioc实现了工厂模式,通过获取application.xml配置文件中的标签的类,注入到ioc容器中,通过构造或set方法注入,产生BeanFactory,BeanFaction通过getBean方法获取对象。

3.什么是依赖注入

在依赖注入中,您不必创建对象,但必须描述如何创建它们。您不是直接在代码 中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。由 IoC 容器将它们装配在一起。

4.spring 中有多少种 IOC 容器

BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端 要求时实例化 bean。 ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它 在 BeanFactory 基础上提供了一些额外的功能。

5.AOP 有哪些实现方式

实现 AOP 的技术,主要分为两大类: 静态代理 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类, 因此也称为编译时增强;  编译时编织(特殊编译器实现)  类加载时编织(特殊的类加载器实现)。 动态代理 在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。  JDK 动态代理  CGLIB

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

简单工厂模式

1.简单工厂模式又叫类的创新型模式,又叫静态工厂方法模型。是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
2.简单工厂模式包含的角色 :

  1. 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
  2. 抽象产品角色:它一般是具体产品继承的父类或者实现的接口
  3. 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
单例模式

1.单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
2.单例模式应用场景 :
重量级对象可以采用单例模式创建。例如配置文件解析器,连接工厂等等。
饿汉单例
线程安全,在类创建的同时就已经创建好一个静态对象供系统使用,以后不再改变。

//饿汉单例
public class Singleton {
	private static final Singleton INSTANCE = new Singleton();

 	// 私有化构造函数
 	private Singleton() {};
 	 public static Singleton getInstance() {
        return INSTANCE;
    }
}

懒汉单例
延时加载。在加载类时创建实例如果在创建实例对象时不加上synchronized 则会导致该对象的访问不是线程安全的。

//懒汉单例
public class Singleto {
	private static Singleton INSTANCE;
	// 私有化构造函数
	 private Singleton() {}public static Singleton getInstance() {
        	if (INSTANCE == null) {
            	INSTANCE = new Singleton();
        }
        	return INSTANCE;
    }
}
	 

二、SpringMVC

1.什么是 Spring 的 MVC 框架

Spring 配备构建 Web 应用的全功能 MVC 框架。Spring 可以很便捷地和其他 MVC 框架集成,如 Struts,Spring 的 MVC 框架用控制反转把业务对象和控制逻 辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。

2.SpringMVC八大步骤

  1. 客户端请求到前端控制器(dispatcherServlet)
  2. 前端控制器(dispatcherServlet)请求处理器映射器(HandlerMapping)
  3. 处理器映射器(HandlerMapping)根据url查找相应的处理器(Handler),返回处理器执行链(HandlerExecutionChain)给前端控制器(DispatcherServlet)
  4. 前端控制器(DispatcherServlet)请求处理器适配器(HandlerAdapter)
  5. 处理器适配器(HandlerAdapter)执行处理器(Handler),生成ModelAndView,返回ModelAndView给前端控制器(DispatcherServlet)
  6. 前端控制器(DispatcherServlet)请求视图解析器(ViewResolver)
  7. 视图解析器(ViewResovler)返回视图对象给前端控制器(DispatcherServlet)
  8. 最后渲染视图
第二种
  1. 客户端发出一个http请求给web服务器,web服务器对http请求进 行 解析,如果匹配前端控制器(或分发器/DispatcherServlet)的请求映射路径, web容器将请求转交给DispatcherServlet.
  2. DipatcherServlet接收到这个请求之后将根据请求的信息以及处理器映射 器(HandlerMapping)的配置找到处理请求的处理器(Handler)。
  3. 由具体的处理器适配器(HandlerAdapter)对Handler进行具体的调用。
  4. Handler对数据处理完成以后将返回一个ModelAndView()对象给 DispatcherServlet。
  5. DispatcherSevlet通过视图解析器(ViewResolver)将ModelAndView()转 化为真正的视图View。
  6. Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展 现出完整的view并返回给客户端。

三、Mybatis

1.Mybatis作用

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

2.Mybatis的好处

把Sql语句从Java中独立出来。封装了底层的JDBC,API的调用,并且能够将结果集自动转换成JavaBean对象,简化了Java数据库编程的重复工作。自己编写Sql语句,更加的灵活。入参无需用对象封装(或者map封装),使用@Param注解
(1)Mybatis对JDBC对了封装,可以简化JDBC代码;(2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;
(3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。
(4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。

3.Mybatis的基本工作流程

  1. 读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。
  2. 加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载
  3. 构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory
  4. 创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法
  5. 当用户使用mapper.xml文件中配置的的方法时,mybatis首先会解析sql动态标签为对应数据库sql语句的形式,并将其封装进MapperStatement对象,然后通过executor将sql注入数据库执行,并返回结果。
  6. 将返回的结果通过映射,包装成java对象。

4.Mybatis是如何将sql执行结果封装为目标对象并返回的? 都有哪些映射形式

第一种是使用标签,逐一定义数据库列名和对象属性名之间的映 射关系。 第二种是使用 sql 列的别名功能,将列的别名书写为对象属性名。有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使用反射给 对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

5.Mybatis 动态 sql 有什么用?执行原理?有哪些动态 sql

Mybatis 动态 sql 可以在 Xml 映射文件内,以标签的形式编写动态 sql,执行原理 是根据表达式的值 完成逻辑判断并动态拼接 sql 的功能。 Mybatis 提供了 9 种动态 sql 标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
在这里插入图片描述

6.Mybatis 的一级、二级缓存

一级缓存:默认开启SqlSession级别的缓存,实现在同一个会话中数据的共享 一级缓存的生命周期和SqlSession一致当有多个SqlSession或者分布式环境下,数据库写操作会引起脏数据。
二级缓存:默认不开启,需手动开启SqlSessionFactory级别的缓存,实现不同会话中数据的共享,是一个全局变量可自定义存储源,如Ehcache当开启缓存后,数据查询的执行的流程是:二级缓存>一级缓存>数据库 不同于一级缓存,二级缓存可设置是否允许刷新和刷新频率实现实体类实现序列化,在mapper文件中开启在配置文件中设置cacheEnabled为true

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的
一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。

二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。

7.在mybatis中#{}占位符和${}占位符有什么区别

#{}:相当于JDBC中的问号(?)占位符,是为SQL语句中的参数值进行占位,大部分情况下都是使用#{}占位符; 并且当#{}占位符是为字符串或者日期类型的值进行占位时,在参数值传过来替换占位符的同时,会进行转义处理(在字符串或日期类型的值的两边加上单引号)

{}: 是为SQL片段进行占位,将传过来的SQL片段直接拼接在${}占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题)

#{}是占位符,使用了预编译处理;${}是拼接符,字符串替换,没有预编译处理。
Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值。

8.Mybaitis的嵌套查询和嵌套结果的区别

嵌套结果的查询:即对于一对多( collection),多对多,多对一(association)的情况的查询,Mybatis通过联合查询,将结果从数据库内一次性查出来,然后根据其一对多,多对一,多对多的关系和ResultMap中的配置,进行结果的转换,构建需要的对象查询需要查询多条数据,而按结果处理只需要一条sql语句就可以完成
嵌套查询的N+1问题
尽管嵌套查询大量的简化了存在关联关系的查询,但它的弊端也比较明显:即所谓的N+1问题。关联的嵌套查询显示得到一个结果集,然后根据这个结果集的每一条记录进行关联查询。现在假设嵌套查询就一个(即resultMap 内部就一个association标签),现查询的结果集返回条数为N,那么关联查询语句将会被执行N次,加上自身返回结果集查询1次,共需要访问数据库N+1次。如果N比较大的话,这样的数据库访问消耗是非常大的!所以使用这种嵌套语句查询的使用者一定要考虑慎重考虑,确保N值不会很大。

四、Springboot(重点)

1.什么是 Spring Boot

Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手
原理
Spring boot是一个脚手架,构建于Spring框架(Framework)基础之上,基于快速构建理念,提供了自动配置功能,可实现其开箱即用特性(创建完一个基本的项目以后,可零配置或者少量配置即可运行我们的项目),其核心主要有如下几个方面:起步依赖(Starter Dependency)-项目创建时底层帮你关联依赖。自动配置(Auto Configuration)。健康检查(Actator)-监控。

2.springboot核心注解

核心注解@SpringBootApplication以及run方法
在这里插入图片描述

  1. @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
    底层核心注解@configuration注解
    能够去注册一些额外的Bean,并且导入一些额外的配置。@Configuration还有一个作用就是把该类变成一个配置类,不需要额外的XML进行配置。
  2. @EnableAutoConfiguration:打开自动配置的功能
    底层核心注解:
    @AutoConfigurationPackage
    让包中的类以及子包中的类能够被自动扫描到spring容器中。
    @Import(AutoConfigurationImportSelector.class)
    这个是自动配置的核心
  3. @ComponentScan:Spring组件扫描。
    扫描包,放入spring容器,那他在springboot当中作用就仅是扫描包那么简单吗?,这个注解要结合SpringBootConfiguration去使用,能选择性的加载需要的类。而不是全部加载。因为内存是有限的。相当于做了一些优化。
  4. @MapperScan(basePackages=“mapper类所在的包”)
    指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类

五、shiro

1.Shiro框架权限管理时的认证和授权流程描述

Shiro权限控制流程的原理:
应用代码 —- 调用Subject (shiro的Subject 就代表当前登陆用户) 控制权限 —- Subject 在shiro框架内部 调用 Shiro SecurityManager 安全管理器 —– 安全管理器调用 Realm (程序和安全数据连接器 )。Subject要进行任何操作,都必须要调用安全管理器(对我们来说是自动的)。而安全管理器会调用指定的Realms对象,来连接安全数据。Realms用来编写安全代码逻辑和访问安全数据,是连接程序和安全数据的桥梁springboot

分布式

一、Linux

1.绝对路径用什么符号表示?当前目录、上层目录用什么表示? 主目录用什么表示? 切换目录用什么命令?

绝对路径: 如/etc/init.d
当前目录和上层目录: ./ …/
主目录: ~/
切换目录: cd

2.怎么查看当前进程?怎么执行退出?怎么查看当前路径?

查看当前进程: ps -ef | grep
执行退出: exit
查看当前路径: pwd

3.怎么清屏?怎么退出当前命令?怎么执行睡眠?

清屏: clear
退出当前命令: ctrl+c
彻底退出 执行睡眠 : ctrl+z
挂起当前进程: fg

4.怎么创建目录?怎么删除文件?怎么复制和移动文件?怎么修改文件?

创建目录:mkdir
删除文件:rm –rf
复制文件:cp
修改文件名,移动文件:mv

二、redis

1.redis是什么

简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以存写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案

2. redis 内存淘汰机制

redis 提供 6种数据淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的).
  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使
    用吧!

3. redis 持久化机制

Redis的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file,AOF)
快照(snapshotting)持久化(RDB)
Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。
AOF(append-only file)持久化
与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:appendonly yes

开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。

4.缓存雪崩和缓存穿透问题解决方案

缓存雪崩

缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉
解决办法

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  2. 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
  3. 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。
缓存穿透

一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量
请求而崩掉。
解决办法

  1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  2. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
  3. 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力
缓存击穿

缓存击穿是指一个key非常热点,在不停的扛着大量的请求,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发直接落到了数据库上,就在这个key的点上击穿了缓存
解决方案

  1. 设置热点数据永远不过期。
  2. 加互斥锁,互斥锁
缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据
解决方案

  1. 直接写个缓存刷新页面,上线时手工操作一下;
  2. 数据量不大,可以在项目启动的时候自动进行加载;
  3. 定时刷新缓存;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值