知识点总结

一、容器

数组(arrayList)与链表(linkedList)的优缺点和区别?

  • 数组:将元素连续存放在内存中,由于每个元素的内存相同,可以直接通过下标迅速访问数组中的元素。如果想要添加或删除元素需要移动大量元素。应用场景在需要快速访问数据时,很少插入和删除的业务场景中。
  • 链表:元素在内存中是无序的,通过元素指针联系在一起,想要访问链表的元素,需要从第一个元素开始,直到找到元素的位置。但是插入、删除非常简单,直接修改元素中的指针就可以。适用于经常插入、删除的需求选用链表。

HashMap原理,如何避免Hash冲突

  • map.put():存储key
  • key.hashCode():获取key的hashCode值,为int类型
  • hash冲突是指两个key通过运算得到的int结果相同。
  • 链表法:防止冲突,Entry有一个next属性,作用是指向下一个Entry。
  • 开放定址法:一旦产生冲突,按照某种规则去寻找另一个空地址。

hashCode和equals区别
hashCode()和equals()作用一样,在java中用来对比两个对象是否一致,由于重写equals比较全面复杂,效率从而就低了。hashCode对比直接生成hash值就可进行比较,效率相对高一些。但是hashCode不是完全可靠,有的时候不同的对象经过计算会生成相同的hashcode,所以hashcode不是完全可靠的。而equals相等的两个对象hashcode肯定相等,属于完全可靠的。hashcode相等的两个对象equals比较不一定相等。

HashMap结构,在jdk1.7和jdk1.8的区别
1.7时采用数组+链表,1.8是采用数组+链表+红黑树结构。红黑树作用是查询和删除效率快,新增慢。

Hashmap为什么线程不安全
原因是在使用put方法时,该方法是不是同步的,如果有两个线程A、B他们的put的key的hash相同,无论是从头插入还是从尾插入,如果A获取插入位置为X,此时B也计算待插入位置为X,无论AB插入的先后顺序肯定有一个会丢失。

Conllection和Conllections区别
Conllection是一个集合接口,提供了对集合对象基本操作的接口方法,直接继承接口有List和Set。
Conllections是集合类的一个工具类,提供静态方法,用于集合元素排序搜索和线程安全的操作。

List、Set、Map之前区别

比较ListSetMap
继承接口ConllectionConllection
常见实现类AbstractList、LinkedList、VectorHashSet、LinkedHashSet、TreeSetHashMap、HashTable
方法add、remove、clear、get、contains、sizeadd、remove、clear、contains、sizeput、get、remove、clear、containsKey、contrainsValue、keySet、Values、size
元素可重复不可重复不可重复
顺序有序无序(由hashcode决定)
线程安全Vector线程安全Hashtable线程安全

HashMap和HashTable区别
hashMap去掉了HashTable的contains方法,加上了containsValue和containsKey方法。
HashMap线程不安全,HashTable线程安全,由于HashMap没有锁性能要高一些。
hashMap允许空键值,而hashTable不允许。

如何决定使用 HashMap 还是 TreeMap
在Map中插入、删除和定位元素这类操作,选择HashMap。如果需要对一个有序的key集合进行遍历,选择TreeMap。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。

HashMap实现原理

  • HashMap是基于哈希表的Map接口的非同步实现,允许使用null值和null键,不保证映射的顺序。
  • HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体
  • Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。

TreeMap

  • TreeMap存储K-V键值对,通过红黑树(R-B tree)实现;
  • TreeMap实现了Cloneable接口,可被克隆,实现了Serializable接口,可序列化;
  • TreeMap因为是通过红黑树实现,红黑树结构天然支持排序,默认情况下通过Key值的自然顺序进行排序;

HashSet 实现原理

  • HashSet的值存放于HashMap的key上
  • HashSet底层由HashMap实现

ArrayList 和 LinkedList区别
ArrrayList底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。

数组与List之间转换
List转换成为数组:调用ArrayList的toArray方法。
数组转换成为List:调用Arrays的asList方法。

ArrayList 和 Vector 的区别
Vector是同步的,而ArrayList不是,ArrayList比Vector快,它因为有同步,不会过载。Vector是线程安全的,ArrayList不是线程安全的。

Array 和 ArrayList区别

  • Array是指定大小的,而ArrayList大小是固定的。
  • Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。

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

Iterator使用和特点

  • Iterator只能单向移动,使用iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
  • 使用next()获得序列中的下一个元素。
  • 使用hasNext()检查序列中是否还有元素。
  • 使用remove()将迭代器新返回的元素删除。

Iterator 和 ListIterator 区别

  • Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
  • Iterator对集合只能是前向遍历,ListIterator既可以前向也可以向后。
  • ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引等等

HashSet插入逻辑
对于HashSet中保存的对象,请注意正确重写其equals和hashCode方法,以保证放入的对象的唯一性。
插入 当有新值加入时,底层的HashMap会判断Key值是否存在(HashMap细节请移步深入理解HashMap),如果不存在,则插入新值,同时这个插入的细节会依照HashMap插入细节;如果存在就不插入。

什么时候扩容
当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值—即当前数组的长度乘以加载因子的值的时候,就要自动扩容啦。
扩容必须满足两个条件:

  • 存放新值的时候 当前已有元素的个数 (size) 必须大于等于阈值
  • 存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值换算出来的数组下标位置已经存在值)

ConcurrentHashMap 的工作原理
ConcurrentHashMap的目标是实现支持高并发、高吞吐量的线程安全的HashMap。

Hashtable底层原理
HashTable类继承自Dictionary类, 实现了Map接口。 大部分的操作都是通过synchronized锁保护的,是线程安全的, key、value都不可以为null, 每次put方法不允许null值,如果发现是null,则直接抛出异常。

put()方法
限制了value不能为null。
由于直接使用key.hashcode(),而没有向hashmap一样先判断key是否为null,所以key为null时,调用key.hashcode()会出错,所以hashtable中key也不能为null。

如何确保集合不能被修改
重写add、remove相关方法,调用时抛出异常。

二、java基础

JVM调优
查看堆空间大小分配(年轻代、年老代、持久代分配)
垃圾回收监控(长时间监控回收情况)
线程信息监控:系统线程数量
线程状态监控:各个线程都处在什么样的状态下
线程详细信息:查看线程内部运行情况,死锁检查
CPU热点:检查系统哪些方法占用了大量CPU时间
内存热点:检查哪些对象在系统中数量最大

什么时候重写equals()方法
从Object里面继承的equal它只是简单比较了一下两个对象的地址是不是同一个,这很明显不符合我们的需求,所以要我们自己重写。

static关键字的场景和意义

  • 静态代码块
  • 修饰类(只能修饰内部类)
  • 修饰成员变量和成员方法

&和&&、|和||区别
&:无论左边是否为false,都会校验右边。
&&:只需要校验左边,如果为false,直接判断结果,不需要继续校验右边,效率上讲比较高。
|和||与&、&&原理相同。
&和|叫做位运算符。

jdk1.8、jdk1.9、jdk10特性
jdk1.8: Lambda表达式,允许把函数作为一个方法的参数,新增了对流的一些接口。
jdk1.9: 新增模块系统,是一个包的容器。
jdk10: 新增var弱类型属性。

接口与抽象的区别
接口: 所有的方法都是抽象方法,没有具体实现,一个接口可以被多个类实现,接口不能实例化自己。
抽象类: 至少包含一个抽象方法,抽象类不能被自身实例化,一个类只能继承一个抽象类,用abstract定义。可以存在成员变量,声明普通方法和抽象方法。
总结:接口一般用于业务层,减少耦合度,使项目更有层次感。抽象类一般用于底层实现。

重载和重写
重载: 参数类型、个数、顺序至少有一个不相同,不能重载只有返回值不同的方法名,存在父类和子类、同类中。
重写: 方法名、参数、返回值相同、子方法不能抛出比父类更多的异常,注意方法被定义为final不能被重写。

java反射原理
java语言编译后会生成.class文件,反射是通过字节码文件找到某个类及类中的方法和属性。

Object常见方法:
toString、equals、hashcode、getclass等。

String、StringBuffer、StringBuilder区别
String: String值是不可变的,每次对String操作时都会生成新的String对象,浪费内存空间,适用于少量字符串操作。
StringBuffer: 多线程下字符缓冲区进行大量操作,属于线程安全的。
StringBuilder: 单线程,是线程不安全的,但是效率比StringBuffer要高一些,是基于StringBuffer后衍生的。

Http协议概述
浏览器根据查询的ip地址与web服务器通信,通信协议就是http协议,端口号默认为80.http基于客户端/服务端(C/S)结构模型,是一个无状态请求、响应协议。

tcp/ip协议

tomcat优化
配置最大线程数,网络连接超时,配置内存大小、禁用DNS查询(修改server.xml文件Connector元素)

GC触发的两种情况

  • 程序调用System.gc手动触发
  • 系统自身决定GC触发的时机

转发(Forward)和重定向(Redirect)的区别

  • 转发是服务器行为,重定向是客户端行为。
  • 转发:通过 RequestDispatcher 对象的forward(HttpServletRequest request,HttpServletResponse response)方法实现的。RequestDispatcher 可以通过HttpServletRequest 的 getRequestDispatcher()方法获得。例如下面的代码就是跳转到 login_success.jsp 页面。
request.getRequestDispatcher("login_success.jsp").forward(request, response);
  • 重定向:是利用服务器返回的状态码来实现的,客户端浏览器请求服务器的时候,服务器会返回一个状态码。
  • 转发url地址不变,重定向url地址改变。转发效率高于重定向。

tcp三次握手

  • 第一次握手:客户端发送带有SYN标志的数据包给服务端。
  • 第二次握手:服务端发送带有SYN/ACK标志的数据包给客户端。
  • 第三次握手:客户端发送带有ACK标志的数据包给服务端。

final、finally、finalize的区别

  • final:修饰符,声明在类上说明该类不能派生出新的子类不能被继承。声明变量上,说明该变量不能被改变,声明的变量必须有初始值,声明后不能被修改。声明在方法上,说明不能再子类中重写。
  • finally:放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。
  • finalize:Object类中定义的方法,该方法由垃圾回收器在销毁对象时调用,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。

Collection和Collections的区别
Collection是一个接口,它是Set、List等容器的父接口;Collections是一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

线程的sleep()方法和yield()方法区别

  • sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会。
  • yield()方法只会给相同优先级或更高优先级的线程以运行的机会。
  • sleep()方法比yield()方法具有更好的可移植性。

明同步和异步
如果正在写的数据可能被另一个线程读到,或正在读的数据可能已经被另一个线程写过,那么这些数据就必须进行同步存取。当程序在对象调用上话费很长时间执行,并不希望等待返回时,可以使用异步编程,异步途径旺旺更有效率。同步就是指阻塞操作,异步就是非阻塞操作。

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

线程池(thread pool)概念
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

线程池操作流程

  • 当一个任务通过submit或者execute方法提交到线程池的时候,如果当前池中线程数(包括闲置线程)小于coolPoolSize,则创建一个线程执行该任务。
  • 如果当前线程池中线程数已经达到coolPoolSize,则将任务放入等待队列。
  • 如果任务不能入队,说明等待队列已满,若当前池中线程数小于maximumPoolSize,则创建一个临时线程

synchronized和Lock区别
Lock 能完成synchronized所实现的所有功能,Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,一般在finally块中释放。

synchronized
线程池参数

  • int corePoolSize :线程池中核心线程数最大值 。线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程。
  • int maximumPoolSize: 线程池中线程总数最大值线程总数 = 核心线程数 + 非核心线程数。
  • long keepAliveTime:线程池中非核心线程闲置超时时长。一个非核心线程,如果不干活(闲置状态)的时长超过这个参数所设定的时长,就会被销毁掉。

JDBC操作数据库步骤

  • 加载驱动
  • 创建连接
  • 创建语句
  • 执行语句
  • 关闭资源

数据库编程时,连接池的作用
由于创建连接和释放连接都有很大的开销,如果数据库服务器不在本地时,每次连接都需要tcp3次握手。为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销,这是典型的用空间换取时间的策略。

三、框架

spring的常用注解

  • @Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
  • @Service用于标注业务层组件。
  • @Controller用于标注控制层组件(如struts中的action)。
  • @Repository用于标注数据访问组件,即DAO组件。
  • @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
  • @Scope用于指定scope作用域的(用在类上)
  • @PostConstruct用于指定初始化方法(用在方法上)
  • @Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
    @Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
  • @Lazy(true) 表示延迟初始化。

Spring BeanFactory与FactoryBean的区别
BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范。
FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式。
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。

SpringAOP的应用场景
场景一: 记录日志
场景二: 监控方法运行时间 (监控性能)
场景三: 权限控制
场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
场景五: 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 )

AOP(面向切面编程)

  • 是一种程序设计泛型,可以成为切面(aspect)的语言构造基础,切面是一种新的模块化机制,用来描述分散在对象、类和方法中的横切关注点。
  • 切面关注是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的,没有必然的联系,但是几乎所有的业务逻辑都会涉及到这些关注功能。事务、日志、安全等就是应用中的切面关注功能。

AOP中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)

  • 连接点(Joinpoint):一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。
  • 切点(Pointcut):如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。
  • 增强(Advice):增强是织入到目标类连接点上的一段程序代码。Spring提供的增强接口都是带方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。
  • 引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。
  • 织入(Weaving):是将增强添加到目标类具体连接点上的过程。
  • 切面(Aspect):切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。

Web项目中配置Spring的IoC容器
在web项目配置文件web.xml中配置:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

Web项目中配置Spring MVC
在web.xml中配置控制器DispatcherServlet:

<web-app>
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
</web-app>

springMVC启动原理

  • 用户发送请求至前端控制器DispatcherServlet,DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle。
  • 处理器映射器根据url获取处理器,生成处理器拦截器和处理器对象返回到DispatcherServlet,DispatcherServlet 调用 HandlerAdapter处理器适配器,HandlerAdapter 经过适配调用 具体处理器Handler。
  • Handler执行完成返回ModelAndView。HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet。
  • DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析,ViewResolver解析后返回具体View。DispatcherServlet对View进行渲染视图,最后响应客户。

常用注解

  • @Controller:标记类上,说明他是一个SpringMVC Controller对象。
  • @RequestMapping:用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
  • @ResponseBody:返回的格式为json、xml等。
  • @Autowired:默认按类型装配,必须依赖对象存在,如果允许null,设置required为false,@Autowired(required=false)
  • @Resource:按照名称装配,可以通过name属性指定,如果没有指定name,默认取字段名进程查找。
  • @Transactional:使用事务或者回滚指定异常。

@Autowired 与@Resource的区别

  • @Autowired//默认按type注入(属于spring的)
  • @Resource(name=“cusInfoService”)//默认按name注入,可以通过name和type属性进行选择性注入(属于J2EE的)

ioc、aop概念
IOC:依赖注入-反射
在spring中,创建被调用者的工作不再由调用者来完成,创建被调用者实例的工作通常由spring容器来完成,然后注入调用者,因此也被称为依赖注入或控制反转。
AOP:面向切面编程
采用动态代理技术,完善spring的依赖注入,面向切面编程在spring中主要表现在声明式事务管理和支持用户自定义切面。

SpringMVC定时任务配置

  • 新建applicationContext.xml(与扫描任务相关)
 <!-- 配置任务扫描 -->
     <task:annotation-driven />
     <!-- 扫描任务 -->
     <context:component-scan base-package="com.xxx.controller" />
  • 创建定时任务类
@Controller
@EnableScheduling
public class TestTask {
    @Scheduled(cron = "0/8 * * * * ? ") // 间隔8秒执行
    public void test() {
        //具体业务逻辑代码
    }
}

springmvc组件介绍

  • DispatcherServlet:中央控制器,把请求给转发到具体的控制类
  • Controller:具体处理请求的控制器
  • HandlerMapping:映射处理器,负责映射中央处理器转发给controller时的映射策略
  • ModelAndView:服务层返回的数据和视图层的封装类
  • ViewResolver:视图解析器,解析具体的视图
  • Interceptors :拦截器,负责拦截我们定义的请求然后做处理工作

spring自动装配bean

  • 隐式的bean发现机制和自动装配
  • 在java代码或者XML中进行显示配置

springBoot配置事务和回滚事务

  • maven导入spring-boot-starter-jdbc依赖,springBoot会自动默认注入。
  • @Transactional 注解在具体业务上

spring boot选择理由
弥补Spring的不足,使编码、配置、部署、监控变简单。

springboot配置文件类型

  • properties:传统配置文件形式。
  • yml:文件更年轻化,通过空格来确定层级关系,更适合做配置文件,目录结构清晰,需要严格遵守空格的用法。

springboot实现热部署

  • spring-boot-devtools
  • spring loaded

SpringCloud
Spring Cloud 就是致力于分布式系统、云服务的框架。Spring Cloud 为开发人员提供了快速构建分布式系统中一些常见模式的工具,例如:配置管理、服务注册与发现、断路器、智能路由、服务间调用、负载均衡、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态、分布式消息等。

spring cloud 断路器的作用
在Spring Cloud中使用了Hystrix 来实现断路器的功能,断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器也能够检测故障是否已经解决,如果检测到问题已经解决,应用程序可以尝试调用操作。

spring cloud 核心组件

  • 服务发现:Eureka
    一个RESTful服务,用来定位运行在AWS地区(Region)中的中间层服务。由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。
  • 客服端负载均衡:Ribbon
    主要提供客户端的软件负载均衡算法。Ribbon客户端组件提供一系列完善的配置选项,比如连接超时、重试、重试算法等。Ribbon内置可插拔、可定制的负载均衡组件。(负载均衡底层原理就是轮询机制,即n台服务端取幂的操作)
  • 断路器:Hystrix
    断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决。如果问题似乎已经得到纠正,应用程序可以尝试调用操作。
  • 分布式配置:Config
    静态的,需要配合SpringCloud实现动态配置更新操作
  • 服务网关:Zuul
    类似nginx,反向动态代理。

Hibernate优点

  • 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码,简化DAO层开发工作。
  • hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
  • hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

hibernate查询方式
hql查询、sql查询、条件查询

hibernate工作流程

  • 通过Configuration config = new Configuration().configure();//读取并解析hibernate.cfg.xml配置文件。
  • 由hibernate.cfg.xml中的读取并解析映射信息
  • 通过SessionFactory sf = config.buildSessionFactory();//创建SessionFactory
  • Session session = sf.openSession();//打开Sesssion
  • Transaction tx = session.beginTransaction();//创建并启动事务Transation
  • persistent operate操作数据,持久化操作
  • tx.commit();//提交事务
  • 关闭Session以及SesstionFactory

get()和 load()的区别
load() 没有使用对象的其他属性的时候,没有SQL 延迟加载
get() 没有使用对象的其他属性的时候,也生成了SQL 立即加载

hibernate缓存

  • 把数据存到内存中,不需要使用流方式,直接从内存读取速度快。
  • hibernate一级缓存默认是打开的。
  • hibernate一级缓存有使用范围。
  • 适用范围是session范围,从创建session到关闭session范围。
  • hibernate缓存中存储数据是持久态数据。
  • hibernate的二级缓存已经不使用了, 用redis替代。
  • hibernate二级缓存默认不是开启的,需要配置。
  • hibernate二级缓存使用范围是sessionfactory范围。

hibernate实体类为什么必须要有无参构造
hibernate框架会调用这个默认构造方法来构造实例对象,即Class类的newInstance方法,这个方法就是通过调用默认构造方法来创建实例对象的。

Hibernate中Session的load和get方法的区别

  • 如果没有找到符合条件的记录,get方法返回null,load方法抛出异常。
  • get方法直接返回实体类对象,load方法返回实体类对象的代理。
  • 在Hibernate 3之前,get方法只在一级缓存中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;load方法则可以从二级缓存中获取数据;从Hibernate 3开始,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。

Query接口的list方法和iterate方法区别
list()方法无法利用一级缓存和二级缓存(对缓存只写不读),它只能在开启查询缓存的前提下使用查询缓存;iterate()方法可以充分利用缓存,如果目标数据只读或者读取频繁,使用iterate()方法可以减少性能开销。

Hibernate实现分页
只需提供HQL语句或查询条件,设置查询其实行数和最大查询行数,并调用Query和Criteria接口的list方法,Hibernate会自动生成分页查询的SQL语句。(调用Session的createQuery()方法)

对象的三种状态

  • 瞬时态:当new实体对象时,就处于瞬时态,这个对象时一个保存临时数据的内存区域,如果没有变量引用这个对象,就会被jvm的垃圾回收机制所回收。这个对象所保存的数据与数据库没有任何关系,除非通过save()、saveOrUpdate()等方法将瞬时态对象与数据库关联,并实现插入或更新操作,才会将对象转换成持久态。
  • 持久态:在数据库中有对应的记录,当进行delete操作后,数据库对应数据删除,则变成瞬时态,既持久态对象改变后不会马上同步到数据库,需要数据库事务提交后同步。
  • 游离态:当Session进行了close()、clear()、evict()或flush()后,对象从持久态变成游离态,对象虽然拥有持久和与数据库对应记录一致的标识值,但是因为对象已经从会话中清除掉,对象不在持久化管理之内,所以处于游离态(也叫脱管态)。

Hibernate常见优化策略

  • 制定合理的缓存策略(二级缓存、查询缓存)。
  • 采用合理的Session管理机制。
  • 尽量使用延迟加载特性。

jpa 和 hibernate区别

  • JPA是Java EE 5的标准ORM接口,也是ejb3规范的一部分。
  • Hibernate是JPA的一个实现,但是其功能是JPA的超集。
  • JPA和Hibernate之间的关系,可以简单的理解为JPA是标准接口,Hibernate是实现。

mybatis 中 #{}和 ${}的区别

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

mybatis分页方式
数组分页、sql分页、拦截器分页、RowBounds分页

mybatis分步查询
通常应用于关联表查询,通常我们关联查询是进行多表联合查询,分布查询时先查询主表,然后通过主表得到的信息将参数传递给关联表,查询关联表的信息。 从代码层面上来说: 关联表能简化代码编写逻辑,减小代码编写难度 从功能层面上来说:关联表只需要查询一次数据库,对于业务量小的系统来说效率更高,数据库压力更小。

mybatis延迟加载
也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。例如在进行一对多查询的时候,只查询出一方,当程序中需要多方的数据时,mybatis再发出sql语句进行查询,这样子延迟加载就可以的减少数据库压力。MyBatis 的延迟加载只是对关联对象的查询有迟延设置,对于主加载对象都是直接执行查询语句的。

mybatis缓存

  • 缓存是计算机中的一块存储区域,把数据存放到存储区域中,读取速度快。
  • 一级缓存:SqlSession级别缓存,默认开启
  • 二级缓存:namespace级别。(一个xml文件对应一个二级的缓存)
  • mybatis开放了Cache接口,整合了第三方缓存。

mybatis 和 hibernate 的区别

  • Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
  • Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,需求变化频繁,一旦需求发生改变可以迅速修改语句。
  • Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。

MyBatis中命名空间(namespace)的作用
每个映射文件起一个唯一的命名空间,在定义映射文件中多个sql语句就成了定义在这个命名空间中的一个ID。只要保证每个命名空间中的这个id是唯一的,即使在不同映射文件中的语句ID相同也不会产生冲突。

MyBatis中的动态SQL元素

  • if
  • choose/when/otherwise
  • trim
  • set
  • where
  • foreach

rabbitmq使用场景

  • 跨系统的异步通信,所有需要异步交互的地方都可以使用消息队列。如:发短信、电子邮件。
  • 多个应用之间解耦,因为消息与平台和语言无关的,基于消息队列的耦合,不需要发送方和接收方同时在线。在企业应用集成(EAI)中,文件传输,共享数据库,消息队列,远程过程调用都可以作为集成的方法。
  • 应用内的同步变异步,比如订单处理,就可以由前端应用将订单信息放到队列,后端应用从队列里依次获得消息处理,高峰时的大量订单可以积压在队列里慢慢处理掉。由于同步通常意味着阻塞,而大量线程的阻塞会降低计算机的性能。
  • 应用需要更灵活的耦合方式,如发布订阅,比如可以指定路由规则。
  • 跨局域网,甚至跨城市的通讯(CDN行业)。

rabbitmq角色

  • 生产者:消息的创建者,负责创建和推送数据到消息服务器。
  • 消费者:消息的接收方,用于处理数据和确认消息。
  • 代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是负责传递。

rabbitmq组件

  • ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。
  • Channel(信道):消息推送使用的通道。
  • Exchange(交换器):用于接受、分配消息。
  • Queue(队列):用于存储生产者的消息。
  • RoutingKey(路由键):用于把生成者的数据分配到交换器上。
  • BindingKey(绑定键):用于把交换器的消息绑定到队列上。

rabbitmq消息发送
客户端连接到 RabbitMQ 服务器发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接,一旦 tcp 打开并通过了认证认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。

rabbitmq保证消息稳定性
提供事务功能,将channel设置为confirm(确认)模式。

rabbitmq解决消息丢失
消息持久化、ACK确认机制、设置集群镜像模式、消息补偿机制。

rabbitmq广播类型

  • fanout: 所有bind到此exchange的queue都可以接收消息(纯广播,绑定到RabbitMQ的接受者都能收到消息);
  • direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息;
  • topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息;

rabbitmq延迟消息队列

  • 通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
  • 使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。

rabbitmq节点类型

  • 磁盘节点:消息会存储到磁盘。
  • 内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。

rabbitmq 集群中唯一一个磁盘节点崩溃
唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。

kafka不能脱离zookeeper单独使用的原因
kafka 使用 zookeeper 管理和协调 kafka 的节点服务器。

kafka数据保留策略
按照过期时间保留和按照存储的消息大小保留。kafka设置时间和大小进行清除数据,无论哪个条件满足了都会清空数据。

kafka集群注意事项

  • 集群不要超过7个,节点越多消息复制需要的时间就越长,整个群组的吞吐量就降低。
  • 集群数量最好是单数,因为超过一半故障集群就不能用了,设置为单数容错率更高。
  • 单数服务器没有超过一般的服务器宕机zookeeper可以正常使用。
    zookeeper介绍
    zookeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 hadoop 和 hbase 的重要组件。为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。(一般与dubbo组合使用)

**zookeeper功能 **

  • 集群管理:监控节点存活状态、运行请求等。
  • 主节点选举:主节点挂掉了之后可以从备用的节点开始新一轮选主,主节点选举说的就是这个选举的过程,使用 zookeeper 可以协助完成这个过程。
  • 分布式锁:zookeeper 提供两种锁:独占锁、共享锁。独占锁即一次只能有一个线程使用资源,共享锁是读锁共享,读写互斥,即可以有多线线程同时读同一个资源,如果要使用写锁也只能有一个线程使用。zookeeper可以对分布式锁进行控制。
  • 命名服务:在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。

zookeeper设置主节点的好处
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以就需要主节点。

zookeeper通知机制
客户端端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,然后客户端可以根据 znode 变化来做出业务上的改变。

ORM框架
对象-映射关系,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。

四、数据库

sql调优

  • 在表中建立索引,优先考虑where、group by使用到的字段
  • 尽量避免使用select ,使用具体的字段代替
  • 尽量避免使用in 和not in,可以用between或者exists代替
  • 用join代替子查询
  • 创建表时根据需求定义字段类型及大小

索引

  • Hash索引和B+ Tree索引,一般使用的是InnoDB引擎,默认的是B+树。
  • 通过创建唯一索引,可以保证数据库表中每一行数据唯一性。
  • 大大加快数据检索速度。
  • 索引之所以查询速度快,是因为将无序的数据变成了相对有序的数据,项目录一样。
  • 索引对于增加、删除、修改的时候速度较慢,原因是需要动态维护数据。
  • 每一个索引都要占用一定的物理空间,没有必要的字段尽量不要设置索引。
  • 聚集索引:聚集索引表示表中存储的数据按照索引的顺序存储,检索效率比非聚集索引高,但对数据更新影响较大。
  • 非聚集索引:非聚集索引表示数据存储在一个地方,索引存储在另一个地方,索引带有指针指向数据的存储位置,非聚集索引检索效率比聚集索引低,但对数据更新影响较小。

数据库死锁概念
起因是并发修改同一条数据,两个用户互相等待对方,就会产生死锁。
解决办法:
使用悲观锁进行控制,采用固定的顺序访问表和行,将大事务拆分多个小事务,有效减少死锁。

分库分表

  • 水平分表:一张表分成多张一样的表
  • 垂直分表:按具体业务分

数据库三范式

  • 第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
  • 第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
  • 第三范式:任何非主属性不依赖于其它非主属性。

ACID是什么

  • Atomicity(原子性):一个事务中所有操作,要么全完成,要么全不完成,不会结束在中间摸一个环节。
  • Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
  • Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
  • Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

char 和 varchar区别

  • char:固定长度类型,如设置char(10),即便输入三个字符,他也占空间10字节,剩下的7个为空字节。
  • varchar:可变长度存储的值是每个值占用的字节再加上一个用来记录其长度的字节的长度。
  • 从空间上考虑 varcahr 比较合适;从效率上考虑 char 比较合适。

float 和 double 的区别

  • float 最多可以存储 8 位的十进制数,并在内存中占 4 字节。
  • double 最多可以存储 16 位的十进制数,并在内存中占 8 字节。

数据库的事务隔离
MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:transaction-isolation = REPEATABLE-READ。

mysql 常用的引擎
InnoDB 引擎,MyIASM 引擎(不提供事务)。

乐观锁和悲观锁
乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。

redis使用场景
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,redis是单线程的。
Redis 使用场景:数据高并发的读写、海量数据的读写、对扩展性要求高的数据。

redis功能
数据缓存功能、分布式锁的功能、支持数据持久化、支持事务、支持消息队列。

缓存穿透怎么解决
缓存穿透:查询一个不存在的数据,由于缓存没命中时需要查询数据库,查不到就不写入缓存,这可能导致不存才的数据每次请求都去查询数据库,造成缓存穿透。
解决方案:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们就把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

redis 支持的数据类型
string、list、hash、set、zset。

保证缓存和数据库数据的一致性
合理设置缓存的过期时间。
新增、更改、删除数据库操作时同步更新 Redis,可以使用事务机制来保证数据的一致性。

redis实现分布式锁
Redis 分布式锁其实就是在系统里面占一个“坑”,其他程序也要占“坑”的时候,占用成功了就可以继续执行,失败了就只能放弃或稍后重试。占坑一般使用 setnx(set if not exists)指令,只允许被一个程序占有,使用完调用 del 释放锁。

五、JVM

jvm运行数据区
程序计数器、虚拟机栈、本地方法栈、堆、方法区。有的区域随着虚拟机进程的启动而存在,有的区域则依赖用户进程的启动和结束而创建和销毁。

堆和栈的区别

  • 栈内存存储的是局部变量而堆内存存储的是实体。
  • 栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短。
  • 栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。

双亲委派模型
如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求(它的搜索范围中没找到所需的类)时,子加载器才会尝试去加载类。

类加载的执行过程

  • 加载:根据查找路径找到相应的 class 文件然后导入。
  • 检查:检查加载的 class 文件的正确性。
  • 准备:给类中的静态变量分配内存空间。
  • 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。
  • 初始化:对静态变量和静态代码块执行初始化工作。

判断对象是否可以被回收

  • 引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题。
  • 可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

jvm垃圾回收算法

  • 标记-清除算法:算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
  • 标记-整理算法:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  • 复制算法:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  • 分代算法:把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
  • 待补充

jvm垃圾回收期

  • CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。
  • G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。

新生代垃圾回收器和老生代垃圾回收器

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G1
  • 新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。

分代垃圾回收器工作原理

  • 分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
  • 把 Eden + From Survivor 存活的对象放入 To Survivor 区。
  • 清空 Eden 和 From Survivor 分区。
  • From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。
  • 每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。
  • 老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。

常用的 jvm 调优的参数
-Xms2g:初始化推大小为 2g;
-Xmx2g:堆最大内存为 2g;
-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
-XX:+PrintGC:开启打印 gc 信息;
-XX:+PrintGCDetails:打印 gc 详细信息。

六、场景

大型网站在架构上应当考虑哪些问题

  • 分层:分层可以有效解决系统复杂性的手段,横切面分为若干个层面,每个层面有单一职责,分工明确。有助于开发和维护,每层负责的事情都比较独立,减少耦合性。
  • 分布式:可以减轻应用服务器的负载压力,让浏览器对资源加载快,还可以使用降级、熔断等保护网站的健壮性给用户更好的体验。
  • 集群:集群使得有更多的服务器提供相同的服务,可以更好的提供对并发的支持。
  • 缓存:合理利用缓存就是空间换时间的理念,节省资源提高效率。
  • 异步:异步是实现软件实体之间解耦合的又一重要手段。异步架构是典型的生产者消费者模式,二者之间没有直接的调用关系,只要保持数据结构不变,彼此功能实现可以随意变化而不互相影响,这对网站的扩展非常有利。

XSS攻击、sql注入攻击、csrf攻击

  • xss:是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式。
  • sqk注入:注入攻击最常见的形式,当服务器使用请求参数构造SQL语句时,恶意的SQL被嵌入到SQL中交给数据库执行。
  • CSRF:是攻击者通过跨站请求,以合法的用户身份进行非法操作,比如转账、发动态等。CSRF的原理是利用浏览器的Cookie或服务器的Session,盗取用户身份。

补充

1.函数与存储过程的区别
①存储过程用户在数据库中完成特定操作或者任务(如插入,删除等),函数用于返回特定的数据。
②存储过程声明用procedure,函数用function。
③存储过程不需要返回类型,函数必须要返回类型。
④存储过程可作为独立的pl-sql执行,函数不能作为独立的plsql执行,必须作为表达式的一部分。
2.having的作用
HAVING语句通常与GROUP BY语句联合使用,用来过滤由GROUP BY语句返回的记录集。
先分组再添加条件

select department,group_concat(salary),sum(salary) from student group by department
having sum(salary)>=9000;

having和where的区别:
having在分组后对数据进行过滤。
where在分组前对数据进行过滤。
having后面可以使用分组函数(统计函数)
where后面不可以使用分组函数。
3.数据不存在则插入,数据存在则更新思路
1.先执行更新操作,如果更新结果大于0则表示数据更新成功,如果更新结果为0,说明数据库没有该条数据,直接插入。
2.编写存储过程。
4.设计模式参考文献

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐