面试话术

601 阅读52分钟

部署activemq

1.上传 2.解压 tar vxzf apache-activemq 3.放到一个新的文件夹下 :mv apache-activemq(要放得文件) activemq(文件夹名称) 4.启动mq需要在bin下,所以先进到bin下 5.启动:./activemq java -version 查看jdk版本

部署zookeeper

1.上传 (直接拉过来) 2.解压 tar vxzf zookeeper... 3.在conf中 复制zoo_sample.cfg 具体代码:cp zoo_sample.cfg zoo.cfg 4.编辑zoo.cfg 修改路径 完成之后,wq保存退出 5.在zookeeper下创建一个文件夹date mkdir data 6.给zookeeper-3.4起别名 zookeeper3.4 zookeeper 7.然后在bin下启动就行了 启动:./zkServer.sh start

AOP:

   代理模式:    (将被代理对象注入给代理对象,当调用代理对象时,实际上是在调用被注入的被代理对象)
                        代理类     被代理类
                      
                     静态代理: 代理类只能代理某一种类,不能代理任何一个类

                     动态代理: 代理类可以代理任何一个类

实现切面的具体代码:
   注解形式:
           1.建立一个切面类  里面加上两个注解    @Component (让spring容器发现这个类)     @Aspect (告诉它这是个切面)
           2.里面写方法       方法上家注解 ,表示这是什么通知,是前置(@before),后置(@),还是异常,环绕或最终通知  
                   还得标明要切的方法是什么,如:@before("execution(*   包名.*.*))  *为包名里的所有类(第一*),所有方法(第二*)

1.tomcat的工作流程是什么? 2.登录里面的token是怎么生成的?token每次是怎么样传回服务端的? 3.session共享有什么办法? 4.锁? 5.redis 缓存? 6.内存模型?

1.什么是线程池,简单说一下几种常见线程池?

java线程池的工作原理和数据库连接池的差不多,因为每次重新创建线程都是很耗资源的操作,所以我们可以建立一个线程池,这样当需要用到线程进行某些操作时,就可以直接去线程池里面找到空闲的线程,这样就可以直接使用,而不用等到用到的时候再去创建,用完之后可以把该线程重新放入线程池供其他请求使用从而提高应用程序的性能。

线程池的核心流程:

1.构建一个 ThreadPoolExecutor 并指定默认要创建的线程的数量 2.通过 threadPool.execute() 去添加一个个要执行的线程即实现了Runable接口的java类 3.在实现了Runable接口的java类的run方法中写入具体的业务代码

线程池的业务场景:

我在工作的时候,当时一个同事给我提了一个需求,目前有大量的图片需要处理生产缩略图并进行加水印,因为按照普通的处理方法一个个的进行处理太慢了,问我有没有好的解决方案,这个时候我就想到了java中的线程池,我构建了一个线程数为5个线程池,然后采用分段批量提取的方式每500条为一组数据进行图片信息的提取,然后再把这些通过Threadpool的execute方法交给线程池中的线程进行处理,即充分使用了CPU硬件资源又加快了大数据情况下程序的处理效率。

我当时在工作的过程中,认识一个做电商的朋友,他们当时公司才起步,很多技术都不成熟,所以就常常和我探讨一些技术问题,有次他向我请教一个问题,问我如何才能提高网站的性能,我根据自己在项目中的经验以及自己以前阅读的关于优化方面的资料给他提出了很多建议,如用lucene进行全文检索,用memcached进行分布式缓存,以及通过spring定时器结合freeMarker模板引擎来生成静态页面,由于要生成的页面的数量比较多,考虑到程序的性能,我建议他结合java的线程池进行工作,这样就可以充分使用了CPU硬件资源又加快了大数据情况下程序的处理效率。

【线程池简述】

线程池中,当需要使用线程时,会从线程池中获取一个空闲线程,线程完成工作时,不会直接关闭线程,而是将这个线程退回到池子,方便其它人使用。

简而言之,使用线程池后,原来创建线程变成了从线程池获得空闲线程,关闭线程变成了向池子归还线程。

2.说一下数据库索引,什么是索引,优点和缺点和几个基本的索引类型?

索引的概念

索引就是为了提高数据的检索速度。 数据库的索引类似于书籍的索引。 在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息。 在数据库中,索引也允许数据库程序迅速地找到表中的数据,而不必扫描整个数据库。

 索引的优点
 创建唯一性索引,保证数据库表中每一行数据的唯一性
 大大加快数据的检索速度,这也是创建索引的最主要的原因
 减少磁盘IO(向字典一样可以直接定位)

索引的缺点

创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加 索引需要占用额外的物理空间 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度

索引的分类

  普通索引和唯一性索引    普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)    唯一性索引:保证在索引列中的全部数据是唯一的    CREATE unique INDEX mycolumn_index ON mytable (myclumn)    单个索引和复合索引    单个索引:对单个字段建立索引    复合索引:又叫组合索引,在索引建立语句中同时包含多个字段名,    最多16个字段    CREATE INDEX name_index ON userInfo(firstname,lastname)    顺序索引,散列索引,位图索引

3.http请求中的中文乱码问题

       通过浏览器访问服务器页面和资源时,不可避免地要传送中文字串,如果客户机与服务器不能用同一码表解析字串,肯定会出现各     种各样的乱码问题。我总结了几个乱码场景及解决办法,如下

  服务器上的中文字串被客户端访问时出现的乱码问题

原因:浏览器在解析中文时,不知道该用什么码表去解析,就会用默认的gb2312去解析,肯定会出现乱码

解决办法:以什么码表写入流,在响应的请求头里就告诉浏览器用什么码表,例子使用utf-8 客户端提交中文到服务端导致的乱码

原因:客户端以UTF-8编码,服务端中的request以默认的Iso8859码表解析

解决办法:告诉request用UTF-8码表解析

多线程:

    进程:当前正在运行的程序,一个应用程序在内存中的执行区域
    线程:进程中的一个执行控制单元,执行路径
            单线程:安全性高,但是效率低
            多线程:安全性低,效率高
    一个进程可以有一个线程,也可以有多个线程
CPU执行线程的随机性 (CPU高速切换导致的)

多线程实现的方式:

方式1:一种方法是将类声明为继承Thread的子类。该子类应重写Thread类的run方法。接下来可以分配并启动该子类的实例。

方法2:另一种方法是声明实现Runable接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。

主方法是多线程????

答:主方法是单线程的,但是可以在主方法中创建多个线程,同事执行(变为多线程) 既然有了继承Thread为何还要整出来实现Runable???? 答:java中是单一继承,如果一个类,继承了一个类,就不能继承其他类。如果要是实现了接口,还可以继承别的类。

    (静态修饰 的方法,可以直接通过{类名。方法名}调用)
    static void  sleep (long millis)   ::让当前进程睡会
    static Thread currentThread()    ::返回当前线程对象
    Thread.currentThread().getName()    直接获取进程的名称
    void serName(String name)  改变线程名称,使之与参数name相同

** 多个线程,一个数据,且并发访问这个数据,就容易出错. 怎么解决??? 答: 这里面需要用到一个synchronized(同步锁),可以修饰代码块和方法,被修饰的代码块和方法一旦被某一个线程访问,则直接锁住,其他的线程将无法访问。 解决1. 同步代码块:(对象锁就是一次只能进一个,别的线程都只能等) synchronized(锁对象){ 这里面是放的需要共享的代码 }

(这个):这个可以是对象锁this,也可以是类锁.class锁

注意:锁对象需要被所有的线程付共享 同步:安全性高,效率低 异步(非同步):正好相反 安全性低,效率高 解决2. 用synchronized修改方法(放在权限修饰符之后 void之前),这个方法就变成了一个同步方法 ,也就是一个方法访问之后,其他线程都无法访问。

同步方法的: static synchronized 是类锁 synchronized 是对象锁

synchronize是一个可重如锁,就是方法里面调用方法。

对于对象,不同的内存地址,就是不同的对象,也是就不同的锁。他们可以同时执行。但是同一个锁的时候,就不可以同时执行。必须一个完成之后,再执行另一个。 (判断是否是同一个对象,不是有名称决定的,而是通过内存地址决定的)

利用实现callable来做多线程: 适用场景:适合于处理大量事务之后,需要返回数据结果的情况下。(基本数据类型不能当做泛型)


注意: 非静态 同步方法的锁对象是this 静态的同步方法的锁对象是当前类的字节码对象 同步方法:使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法全部锁住,其他线程则无法访问

意外收获:对于sleep()方法,我们首先知道他是属于Thread类中的。而wait()方法,则是属于Object类中的。 sleep()方法导致了程序暂停执行指定的时间,让出CPU给其他的线程,但是他的监控转态依然保持着,当指定的时间到了之后,他会自动恢复成运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。 而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行转态。 sleep()必须捕获异常,而wait,notify和notifyall不需要捕获异常。


线程的生命周期?(一个对象的生老病死)


linux讲解

1.linux操作系统比较稳定(世界级巨头计算机,各个行业软件服务器系统都是采用的这种语言,常见的就是系统开发人员,运维人员,程序开发人员) 2.要学习找资料鸟哥linux私房菜这本书可参照。

WebService && CXF的讲解

WebService是JDK自带的,相当于JDBC   (也就是 底层实现)
CXF是基于WebService的框架,相当于Hibernate/mybatis    (也就是 框架)

讲解CVS,SVN(集中式)与Git(分布式版本控制系统)

一:Git简介

集中式版本控制系统:版本库是集中存放在中央服务器的,用时拿出来,用完再放进去 。最大的缺点就是必须联网才能工作,网慢还受影响。 分布式版本控制系统:1.它相对于集中式的来说,没有“”中央服务器“”,所以每个人的 电脑都是一个完整的版本库,这样工作的时候就不需要联网, 2.和集中式相比,分布式的更安全,因为每个人电脑里都有完整的版本库,一个人的 电脑坏了,直接从别人那直接复制一个就可以了。而集中式的中央服务器要是坏了,所有人都 不能干活了。( 对了,别忘了,他还是开源的,免费的,哈哈)。 3.在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库 的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天 你的同事病 了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的 修改,没有它大家也一 样干活,只是交换修改不方便而已。 CVS的弊端:1.由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。 2.同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目 前用 得最多的集中式版本库控制系统。 3.除了免费的外,还有收费的集中式版本控制系统,比如IBM的ClearCase。

二:安装

第三方登录(话术)

第三方登录采用国际通用的OAtuth协议。首先需要去第三方注册账号,获取到唯一性的id和cecret安全码,然后在我们的网站上添加第三方的登录图标。例如QQ图标,微信什么的。接下来呢,就是一个三次握手,第一次呢就是,当用户点击这个图标时,跳转到第三方的登录页面,用户登录后会直接跳转到我们的回调地址,并且发送给我们一个code随机码。这样第一次握手就完成了。然后我们将这个code随机码和id,seret安全码发送给第三方(利用HttpClient,发送的post请求)。这时候第三方会返回给我们一个token令牌(其中包含了第三方的一些相关信息)。这样第二次握手就算完成了。但是这次获取到的信息一般不全,所以我们还需要根据用户绑定的状态再一次查询。也就有了第三次握手。第三次在利用token码在发送请求。(一般是为了获取用户名,头像,性别,住址)。假如是第一次登陆,我们会给第三方发送一个绑定账号的请求,将我们的网站与第三方网站绑定。之后跳转到用户信息完善页面,让用户把信息补全。最后将第三方账号信息保存到我们自己的数据库中。假如之前登陆过,那么我们会根据用户信息到自己的数据库中查询出之前添加的信息,并保存在session中,然后跳转到首页,这样第三次握手就算完成了。也就完成了第三方账号在我们网站的登录。

电商如何处理高并发的情况

处理高并发的情况,一般我们想到的是通过分流的方式,加快系统的吞吐量,和业务的优化这三方法。在分流方面我们采用的是用Ngnix做负载均衡和反向代理。在系统吞吐量上我们采用的是redis做缓存处理。在文件的存储上我们可以采用fastdfs做存储。页面呢可以用freemarker静态化技术做静态页面。与数据库有关的业务可以采用分库分表的形式,来提供数据库的效率。方法呢有很多,主要呢就是根据系统的压力和场景来选择适合自己网站的方式就可以了。

关于支付的话术

其实所有的第三方支付都差不多,就是根据他们提供额文档直接写实现自己的业务逻辑就可以了,他们的接口需要什么样的数据,就给他们什么样的数据就可以了。支付成功后会跳转到我们的回调接口。(网站想要与第三方登录平台对接,就需要先去该平台注册商户号以及商户秘钥)

支付宝支付:

买家点击确认付款后我们会根据订单号去调用订单服务提供的dubbo获取该订单的信息。同时我们会给支付宝发送一个请求,(当中包含商户号,秘钥,回调地址,加密签名(MD5加密(编号+商户号+总价格))等支付信息)。并将支付信息保存到我们的订单表以及订单详情表中。同时页面也跳转到支付宝的支付页面。买家支付完成后,支付宝会把支付结果发送给我们的回调地址。支付结果中会有一个通知id,我们需要将通知id作为参数调用支付宝给我们的支付结果查询接口。去查询支付结果是否正确。主动查询主要是为了,防止我们的回调地址泄露。查询结果接口会给我们返回一个以XML形式的查询信息。告诉我们该通知id是否是以支付宝发起,并且该支付信息是否有效。我们还需要根据用户的实际支付金额和理应支付金额做判断,如果一直,并且通知id也有效,那么久认为该用户支付成功。然后根据用户信息跳转到支付结果页面,并且更新数据库中的支付信息。这样支付就完成了。

微信支付:

订单管理

首先是订单表的设计,主要包括订单表和订单详情表,订单表主要包含订单的主要信息,比如订单的编号、总额、数量、状态、收货人信息等。其中收货人信息必须要冗余到订单表中,不能简单用Id进行管理。订单详情表和订单表是多对一关系,订单详情表主要计量订单中的商品的详细信息,这些信息也要冗余进来,不能通过id进行简单的关联,因为订单一旦生成,这些信息一般不会再允许改变。

订单在用户结算购物车时生成,如果同时购买多个商家的商品,在结算购物车时需要进行分单,同时生成多张订单。在用户中心,每个用户都可以看到并跟踪自己的订单,进行支付、申请退货、确认收货、评价等操作。商家后台可以看到商家自己的所有订单,进行确认发货操作。而在运营管理平台,可以监控所有的订单,但是不能进行操作。

订单的状态主要包括:待支付、待发货、已发货、已完成、已取消;

生成订单时,应该对库存进行一次校验,防止超卖;

单点登录

我们的单点登录系统,主要包含了登录验证、token校验、注销、注册几大功能,单点登录系统提供了统一的登录和注册页面,提供了统一的登录token校验接口。

单点登录的主要原理就是在登录成功以后,生成一个令牌,这个令牌要求每次登录唯一不可重复,我们就简单的用了一个随机的UUID,因为我们的系统在部署时,各个模块都是通过Nginx映射到同一个一级域名下的,cookie只要把他的作用域设置成一级域名,就可以在所有同一个一级域名下的模块中共享。所以我们把随机生成的token,以字符串 “token”为key,放在cookie里边,然后用生成的token做key,用户对象信息转成json字符串后,作为value,放到redis里边,都设置有效期30分钟;

然后做了一个统一校验token的接口;各个模块在自己的拦截器里边,调用此token校验接口,验证是否登录,如果返回null,则说明没有登录,拦截到统一的登录页面,并把进入拦截到的url放入cookie里边,方便登录成功以后,获取这个url,进行原路径跳转,而不是每次登录都进入首页,提供用户的体验度。如果返回用户信息,则说明已经登录,模块创建自己的session,并放行url。统一校验token的接口的主要流程是,首先从cookie里边获取到token,然后通过token到redis里边获取用户信息。这两个过程,任何一个失败,都直接返回null,如果成功,就把cookie和token的值从新设置一遍(这个是为了刷新有效期);?这样就实现了多个模块只需要登录一次就可以的流程。

还有就是注销,注销也是调用统一的注销接口,注销时需要首先从cookie中获取token,根据token删除redis中的用户信息,然后在删除cookie中的token。

MQ消息队列

MQ简称消息队列,他是一个不同项目之间进行通讯时,对消息进行管理的组件。有了MQ,可以使项目之间交互由同步转换成异步,解耦了消息的处理过程。把消息统一管理起来,按照顺序,根据客户端的处理能力一个一个的进行操作,MQ具有送达保证、排序保证、峰值处理、异步通信几大特性。在高并发时,对于减轻数据库压力非常有效。MQ一般有点对点和发布订阅两种方式,点对点就是一个消息只允许接收一次,发布订阅模式,一个消息可以被多次接收。目前主流的产品有RabbitMQ、ActiveMQ和Kafka;ActiveMq是Java语言开发的,RabbitMQ是Erlang语言开发的,理论上,RabbitMQ的性能比ActiveMq更强,是非Java系统的首选,ActiveMq是Java的,整套系统如果本来就是Java的,配合的默契更佳。Kafka相当于一个分布式的MQ,传统的MQ,消息被消化掉后会被mq删除,而kafka中消息被消化后不会被删除,而是到配置的expire时间后,才删除,他把写入压力均摊到各个节点。可以通过增加节点降低压力;

anjularJS

AngularJS 是一个 JavaScript 框架。它是一个以 JavaScript 编写的库。它一般用在 数据操作比较多的应用。为了实现这些,AngularJs引入了一些非常棒的特性,包括模板机制、数据绑定、指令、依赖注入、路由等。数据绑定可能是AngularJS最酷最实用的特性。通过数据与模板的绑定,能够让我们摆脱繁琐的DOM操作,而将注意力集中在业务逻辑上。AngularJS内置了很多指令用来控制模板,如ng-repeat,ng-class等,也有很多指令来帮我们完成业务逻辑。还有AngularJS服务啊路由之类的功能也都是非常实用的。AngularJS不依赖(也不妨碍)任何其他的框架,我们甚至可以基于其它的框架来开发AngularJS应用。在我们之前的一个项目中也用到了AngularJS,通过AngularJS,我们实现了前后端分离开发,前端使用路由,页面的性能会有很大的提升,同时也会减少后端的压力,页面跳转可以不需要经过后端,后端只负责提供数据做为展示。

HTTPClient

HttpClient字面理解就是http请求的客户端,他是Apache开发的一套HTTP协议的客户端编程工具包。是纯Java语音编写的,支持https协议,实现了http的get、post、delete、put等全部方法,但我们一般只用get和post方法,用httpclient可以直接跨域请求http协议的url,并拦截返回的响应结果。

我们项目里边有写好的工具类,里边封装好了他的get和post方法,传入url和参数,返回String类型数据(一般是json字符串或xml字符串),然后我们进行解析就可以了。

他的调用步骤是:

1.创建HttpClient对象。

2.创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。

3.如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。

4.调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。

5.调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。

6.释放连接。无论执行方法是否成功,都必须释放连接

Shiro

Apache Shiro是java的一个安全框架,比Spring Security要简单的多,但是没有Spring Security他的功能强大。Shiro主要有登录认证,授权,会话管理这三大功能。另外添加了加密、缓存、web基础等功能。但它不会去维护用户和权限。这个还需要我们自己去完成。它的基本工作流程就是:首先我们通过SecurityUtils来获取Subject,用它来进行认证和授权,然后通过安全管理器securityManager来管理所有的Subject. 给Shiro的securityManeger中注入Realm.通过realm获取相应的用户进行比较来确定用户身份是否合法。同时也需要中得到用户相应的角色和权限进行用户验证是否可以进行操作。框架中使用一般是,先导入相关jar包,web.xml中加shiro-filter过滤器,配置shiro.xml,里边配置过滤器和安全管理器,还可以自定义form 认证过滤器、自定义realm(领域)、加密等。他提供了多种授权方式;编程授权、注解授权、jsp标签授权。

springboot和springcloud

spring boot 我理解就是把 spring,spring-mvc,spring-data-jpa 等等的一些常用的常用的基础框架组合起来,提供默认的可插拔的设计配置。spring boot对spring的配置进行简化,几乎零配置。同时对spring 需要的jar 也进行了整合,解决jar冲突的问题。可以理解为springMvc的升级版。提供了spring-boot-starter-parent的整合工具包。集成了它以后,项目中大部分jar包就不再引用了。内置了Tomcat插件,可以直接用main方法运行;

spring_cloud是基于spring_boot的微服务分布式架构,他主要包括:

服务注册中心:Eureka Server 服务注册者客户端:Eureka Client 服务消费端:负载均衡客户端:ribbon和feign 断路器Hystrix 路由网关zuul(Zuul的主要功能是路由转发和过滤器,zuul默认和Ribbon结合实现了负载均衡的功能。)

事务的隔离级别

     脏读:一个事务看到了另一个事务没有提交的更新数据。
     不可重复:在同一事物中,多次读取数据但是返回不同的结果。
     幻读:一个事务在执行过程中读取到另一个事务已提交的插入数据。这是并发造成的。

事务的传播特性

  1. requierd: 如果当前没有事务,就新建一个事务,如果有事务,就加入这个事务中。
  2. requierd_new: 新建事务,如果当前有事务,就把当前事务挂起。
  3. supports: 支持当前事务,如果当前没有事务,就以非事务方法执行。
  4. not_supports: 就以非事务方法执行,如果当前存在事务,就把事务挂起。
  5. mandatory: 使用当前事务,如果没有当前事务就抛异常。
  6. never: 就以非事务方法执行,如果有事务就抛异常。
  7. nested: 如果当前存在事务,就嵌套在事务内执行。如果当前没有事务,就执行与 required类似的操作(相当于如果没有就是默认required)。 required(必修的) mandatory(强制性的) nested(嵌套的)

利用docker部署(基本话术)

利用docker做项目部署,首先得知道Dockerfile,dockerfile其实就是一些脚本,就是能把代码变成镜像的一种脚本。他和maven插件的功能是一样的。这需要好几步才能实现,所以为了方便,又需要借助jenkins,jenkins算是一种工具,他把dockerfile的步骤放进了jenkins中,然后只需要一个按钮,就能实现dockerfile的功能。所以只要配好了jenkins是就方便了好多。二Gogs是jenkins中的一个东西。比较难懂的一个。

Nginx负载均衡是怎么搭建的?

首先,在linux下装一个Nginx,必须要有依赖,如:prce正则依赖。还有pcc,c++等。依赖都配置好后才可以装nginx。Nginx集群主要是nginx.conf中配置,conf中的service中location下的proxy_pass配置一个tomcat服务中的引用,另外还要配置一个upstream中ip地址端口号,service中tomcat的引用的是upstream的名字。另外,负载均衡实在upstream中配置,来引用的tomcat的IP地址和端口号后面跟一些参数,来配置权重,参数有weigt,backup等等。

session共享是怎么做的?

使用Nginx做的反向代理。session共享实现有多种方式,比如可以自己写一个filter来拦截请求,然后从请求中取得session的id,然后根据session的id在缓存中查找对应的session。但是我用的是spring对session的管理。实际上spring对session的管理也是基于filter实现的。(如果细问怎么做的,就这样回答:1.先导入依赖。2.在web.xml中配置一个filter的过滤器。3.在spring配置文件中,配置spring对session管理的实现。4.把redis集成在项目)

JVM

堆: 分为两部分新生代和老年代(老年代:需要长时间保留的;新生代:用完就得销毁的) 都会先放在新生代中,等到他年龄大的一定的时候,就会放在老年代中(经历了很多次都没有被清理的) 新生代的扫描策略和老年代的扫描策略是不一样的。 新生代:可以分为三部分(伊甸园,S0(From),S1(To)) 根据执行GC()的次数, S0,S1是两块大小相等,功能相同的内存空间。同一时间,只能有一个在(使用)运行转态。(为了时刻都在 紧挨着) 栈: 一个栈有三部分:(局部变量表,操作数栈和帧数据区)

java虚拟机原理:系统虚拟机和程序虚拟机 虚拟机的结构:类加载子系统,堆,栈,直接内存,方法区,本地方法栈,执行引擎,垃圾回收机制,PC收集器

重要的一些概念:

  1. 在java中对象实例都是在堆中创建的,一些类信息,常量,和静态变量回放在方法区中,这个堆和方法区都是线程共享的。 2.GC机制是有JVM提供的,用来清理需要清理的对象,回收堆内存的。 3.GC机制是将java程序员从内存管理中解放出来的,所以它更关注于业务逻辑。 4.在java中,GC是有一个叫垃圾回收器的守护线程所执行的。 5.在内存中回收一个对象,首先就需要调用finalize()方法。 6.作为一个java程序员,不能强制JVM执行GC,这个是由堆内存的大小决定的。 7.System.gc()和Runtime.gc()会向JVM发送执行GC的请求,但是JVM不一定会执行。 8.如果堆没有新的内存创建新的对象了,那么会抛出OutOfMemoryError.

哪些对象回呗GC回收呢???

一般GC需要有三件事需要做:1.那些对象需要被回收 2.何时回收这些对象 3.采用什么样的方式可以回收(常见的有引用计数法) 引用计数法:给对象添加一个引用计数器,每当有一个地方引用了,计数器就+1,当引用失效后,计数器就-1;在任何时候计数器都为0时,就表示这个对象不可能被使用。 当一个对象通过一系列的根对象都不可达时就会被回收。通俗易懂的就是:当一个对象的所有引用都为null.

GC的算法有哪些?

1.复制算法:就是有两个相同的区域,每次只使用一个其中一个(堆中的年轻代的处理方法就是复制算法) 2.标记清除算法:就是先标记处所有需要回收的对象,然后统一回收。 3.标记整理算法:就是先标记出所有需要的回收对象,只不过是先整理一遍,就是让所有存活的对象都向一端移动,然后清理。

SQL的优化

导致查询慢的原因:

1.数据量过大
2.表设计不合理
3.sql语句写的不好
4.没有合理使用索引

针对sql语句的优化:

1.查询中不适用*
2.尽量减少子查询,使用关联查询(left join,right join  等等)替代
3.合理的增加冗余字段
4.建表的时候能使用数字类型的字段就使用数字类型字段,因为数字类型的字段比字符类型的要查询起来快的多。
5.哪些可以过滤掉最大数量记录的条件必须写在where字句的最末尾

说索引前,显了解一下这个explain(查看sql的执行计划):

最终要的就是:
select_type:sql语句的难易程度;
type:表示表的连接类型(ALL:说明对表进行了完成的)
rows:查询是受影响的行数。

补充: (使用explain查看sql执行计划后,我们主要先看下type属性,表示连接的类型,如果是ALL这种那就需要优化了, 再看下possible_key属性,表示可以使用的索引,如果没有则为null,key属性表示mysql实际决定使用的索引,如果没有选择索引,键是null, rows 表示mysql认为它执行查询时必须检查的行数,行数越多效率越低。)

索引的类型:一般分为:主键索引,唯一索引,组合索引,普通索引。 什么是索引:数据库索引是数据库管理系统中的一个排序的数据结构,以协助快速查询,更新数据 库表中数据,索引的实现通常使用B树(B-tree)以及其变种B+tree(一些高效率的算法)

注意事项:

1、使用like关键字模糊查询时,% 放在前面索引不起作用,只有“%”不在第一个位置,索引才会生效(like '%文'--索引不起作用) 2、使用联合索引时,只有查询条件中使用了这些字段中的第一个字段,索引才会生效 3、使用OR关键字的查询,查询语句的查询条件中只有OR关键字,且OR前后的两个条件中的列都是索引时,索引才会生效,否则索引不生效。 4、尽量避免在where子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。 5、对查询进行优化,应尽量避免全表扫描,首先应考虑在where以及order by涉及的列上建立索引。 6、应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:   select id from t where num/2=100   应改为:   select id from t where num=100*2 7、尽量避免在where子句中对字段进行函数操作,将导致引擎放弃使用索引而进行全表扫描。 8、不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 9、并不是所有的索引对查询都有效,sql是根据表中的数据来进行查询优化的,当索引列有大量数据重复时,sql查询不会去利用索引,如一表中有字段   sex,male,female几乎个一半,那么即使在sex上建立了索引也对查询效率起不了作用。 10、索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,   因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,   若太多则应考虑一些不常使用到的列上建的索引是否有 必要。 11、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。   这是因为引擎在处理查询和连接时会 逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。 12、mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。    因此数据库默认排序可以符合要求的情况下不要使用排序操作,尽量不要包含多个列的排序,如果需要最好给这些列建复合索引。 13、order by 索引 ,不起作用的问题(除了主键索引之外):   1、 如果select 只查询索引字段,order by 索引字段会用到索引,要不然就是全表排列;

   2、如果有where 条件,比如where vtype=1 order by vtype asc . 这样order by 也会用到索引!

总结(优化数据库的八种方法): 1.选取最适用的字段属性 2.使用连接(join)来代替子查询。 3.使用联合(UNION)来代替手动创建的临时表 4.事务 5.锁定表 6.使用外键 7.使用索引 8.优化的查询语句

死锁

什么是死锁?

  标准定义:
  自己的理解:一座独木桥上有两辆车,此刻都在桥上(谁也不能前进,谁也不能后退),就这样耗着。形成死局面。

产生死锁的必要条件:

  1.互斥条件:如独木桥就是一种独占资源,两方的人不能同时过桥。
  2.不可抢占条件:如过独木桥的人不能强迫对方后退,也不能非法地将对方推下桥,必须是桥上的人自己过桥后空出桥面(即主动释放占有资源),对方的人才能过桥。
  3.占有且申请条件:甲过不去,前进不能,又不后退;乙也处于同样的状况。
  4.循环等待条件:就像前面的过独木桥问题,甲等待乙占有的桥面,而乙又等待甲占有的桥面,从而彼此循环等待。

死锁的预防:

方法:只要破坏了前面提到的四个必要条件中的任意一个条件,死锁就不会发生。(一般地,解决死锁的方法分为死锁的预防,避免,检测与恢复三种) 具体方法:也就是打破四个必要因素。 死锁的恢复: 一旦在死锁检测时发现了死锁,就要消除死锁,使系统从死锁状态中恢复过来。

(1)最简单,最常用的方法就是进行系统的重新启动,不过这种方法代价很大,它意味着在这之前所有的进程已经完成的计算工作都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程。

(2)撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。这时又分两种情况:一次性撤消参与死锁的全部进程,剥夺全部资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。一般来说,选择逐步撤消的进程时要按照一定的原则进行,目的是撤消那些代价最小的进程,比如按进程的优先级确定进程的代价;考虑进程运行时的代价和与此进程相关的外部作业的代价等因素。 

此外,还有进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时不再发生死锁。虽然这是个较理想的办法,但是操作起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便今后的回退,有时这是无法做到的。

搜索引擎——solr

什么是solr?

solr是一个开源的搜索平台,用于构建搜索应程序。它建立在Lucene(全文搜索引擎)之上。solr是企业级的,快速的和高度可扩展的。

Maven

Maven是一个项目管理工具,其核心特点就是通过maven可以进行包的依赖管理,保证jar包版本的一致性,以及可以使多个项目共享jar包,从而能够在开发大型应用的时候,减小项目的规模。

为了节省下jar包的时间?我们可以采用了nexus搭建了在局域网内的maven私服,然后通过配置settings.xml中建立mirror镜像,将所有下载jar包的请求都转发到maven私服上,之后通过在pom.xml,及中配置项目所依赖的jar包,从而达到在构建项目的时候,先从本地仓库中查找,如果不存在从内部私服查找,如果不存在最后再从外网central服务器查找的机制,达到了节省下载宽带,提高开发效率,以及jar包重用的目的。

spring中的IOC和AOP(话术)

IOC: ioc另外一种说话叫做DI,既依赖注入。它并不是一种技术实现,而是一种设计思想。在任何一个实际开发意义的程序项目中,我们会使用很多的类来描述他们特有的功能,并且通过类与类之间的相互协作来完成特定的业务逻辑。这个时候,每个类都需要负责管理与自己有交互的类的引用和依赖。这时候代码将变得异常难易维护和极度的高耦合。而IOC的出现真实来解决这个问题的。我们通过IOC将这些相互依赖对象的创建、协调工做交给spring容器来处理,每个对象只需要关注其自身的业务逻辑就可以了。在遮掩那个的角度上来看,获得依赖的对象方式,进行了反转,变成了与spring容器控制对象如歌获取外部资源。(举例:就是头疼病人去医院买药的例子。自己选药很难受,所以就直接找医生,让医生配药,直接吃就好。IOC起到的就是医生的作用,他收集你的需求要需,并且对症下药。直接开药给你。你就是对象,药品就是你所需要的外部资源。)

什么是AOP? 面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 1.面向切面编程提供声明式事务管理 2.spring支持用户自定义的切面

面向切面编程(aop)是对面向对象编程(oop)的补充, 面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程中的步骤进行抽象,,从而获得步骤之间的逻辑划分。

aop框架具有的两个特征: 1.各个步骤之间的良好隔离性 2.源代码无关性

Spring的事务管理机制实现的原理,就是通过这样一个动态代理对所有需要事务管理的Bean进行加载,并根据配置在invoke方法中对当前调用的 方法名进行判定,并在method.invoke方法前后为其加上合适的事务管理代码,这样就实现了Spring式的事务管理。Spring中的AOP实 现更为复杂和灵活,不过基本原理是一致的。

Lucene原理

Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。lucene 能够为文本类型的数据建立索引,所以你只要能把你要索引的数据格式转化的文本的,Lucene 就能对你的文档进行索引和搜索。比如你要对一些 HTML 文档,PDF 文档进行索引的话你就首先需要把 HTML 文档和 PDF 文档转化成文本格式的,然后将转化后的内容交给 Lucene 进行索引,然后把创建好的索引文件保存到磁盘或者内存中,最后根据用户输入的查询条件在索引文件上进行查询。

索引和搜索: Lucene 采用的是一种称为反向索引(inverted index)的机制。反向索引就是说我们维护了一个词 / 短语表,对于这个表中的每个词 / 短语,都有一个链表描述了有哪些文档包含了这个词 / 短语。这样在用户输入查询条件的时候,就能非常快的得到搜索结果。搜索引擎首先会对搜索的关键词进行解析,然后再在建立好的索引上面进行查找,最终返回和用户输入的关键词相关联的文档。对于中文用户来说,最关心的问题是其是否支持中文的全文检索。由于Lucene良好架构设计,对中文的支持只需对其语言词法分析接口进行扩展就能实现对中文检索的支持。

索引步骤: 1.获取内容:lucene作为一款核心搜索库,不提供任何功能来实现内容获取。利用大量的开源爬虫软件实现这个功能 2.建立文档:获取原始内容后,需要对这些内容进行索引,必须将这些内容转换成部件(文档)。文档主要包括几个带值的域,比如标题,正文,摘要,作者和链接。如果文档和域比较重要的话,还可以添加权值。 3.文档分析:搜索引擎不能直接对文本进行索引:必须将文本分割成一系列被称为语汇单元的独立的原子元素。每一个语汇单元能大致与语言中的“单词”对应起来,这个步骤决定文档中的文本域如何分割成语汇单元系列。lucene提供了大量内嵌的分析器可以轻松控制这步操作。 4.文档索引:将文档加入到索引列表中。Lucene在这一步骤中提供了强档的API,只需简单调用提供的几个方法就可以实现出文档索引的建立。为了提供好的用户体验,索引是必须要处理好的一环:在设计和定制索引程序时必须围绕如何提高用户的搜索体验来进行。

Elasticsearch简介:

Elasticsearch是一个实时的分布式搜索和分析引擎。它可以帮助你用前所未有的速度去处理大规模数据。它可以用于全文搜索,结构化搜索以及分析,当然你也可以将这三者进行组合。

ES的优点:

1.Elasticsearch是分布式的。不需要其他组件,分发是实时的。 2.Elasticsearch 完全支持 Apache Lucene 的接近实时的搜索。 ES的缺点: 1.只有一个开发者。 2.还不够自动。

Solrs简介:

    Solr是最流行的企业级搜索引擎。Solr是用Java编写、运行在Servlet容器。的一个独立的全文搜索服务器。Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具有类似REST的HTTP/XML和JSON的API。Solr强大的外部配置功能使得无需进行Java编码,便可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制。

优点:

1.Solr有一个更大、更成熟的用户、开发和贡献者社区。 2.支持添加多种格式的索引,如:HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。 3.Solr比较成熟、稳定。 4.不考虑建索引的同时进行搜索,速度更快。 缺点: 1.建立索引时,搜索效率下降,实时索引搜索效率不高。 2.当单纯的对已有数据进行搜索时,Solr更快。 3.当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。 4.随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。 5.综上所述,Solr的架构不适合实时搜索的应用。

Elasticsearch 与 Solr 的比较总结:

1.二者安装都很简单; 2.Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能; 3.Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式; 4.Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供; 5.Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。 6.Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。

*****************************************mongodb简介 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。 特点: 1.它的特点是高性能、易部署、易使用,存储数据非常方便。 2.模式自由。 3.支持动态查询。 4.支持完全索引,包含内部对象。 5.支持查询。 6.支持复制和故障恢复。 7.使用高效的二进制数据存储,包括大型对象(如视频等)。 使用原理: 所谓“面向集合”(Collection-Oriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。Nytro MegaRAID技术中的闪存高速缓存算法,能够快速识别数据库内大数据集中的热数据,提供一致的性能改进。 MongoDB适用的场景: 1.网站实时数据处理:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。 2.缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。 3.高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。 MongoDB不适用的场景: 1.要求高度事务性的系统。 2.传统的商业智能应用。 3.复杂的跨文档级联查询。

数据模型:一个MongoDB 实例可以包含一组数据库,一个DataBase 可以包含一组Collection(集合),一个集合可以包含一组Document(文档)。一个Document包含一组field(字段),每一个字段都是一个key/value pair。 key: 必须为字符串类型。 value:可以包含如下类型。 ● 基本类型,例如,string,int,float,timestamp,binary 等类型。 ● 一个document。 ● 数组类型。

**********************************************Websocket(HTML5出的东西) 要想了解websocket,我们首先需要了解http协议。websocket是一个新协议,跟http协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是它是HTTP协议上的一种补充。有交集但是并不是全部。

Wrbsocket的优点:持久性,被动性(就是服务器可以主动给客户推送消息了,HTTP不可以。)

介绍Websocket之前需要先说一下这个,long poll和ajax的原理。 ajax轮询(需要更快的速度):让浏览器隔几秒就发送一次请求,询问服务器是否有新信息。 long poll(需要更多的电话):它的原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直 打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。 直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。

Websocket的作用:

 只要websocket连接成功后,之后就可以源源不断的传递消息了;只需要确认一次身份信息,就再也不用了。比http要效率高,这也就是他的持久性。
 被动性就是,就是websocket连接成功后,服务端可以直接给客户端推送消息,而传统的http是不可以的。

传统的HTTP协议是无转态的。

Websocket的工作流程:

    浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多。本文不详

细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。

Websocket里面的注解: @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, 11 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端

分布式事务

正常的:就是用的事务管理器(transactionManager)

在分布式的项目里,用的是分布式事务管理。不同的框架,使用不同的分布式事务。dubbo框架、springcloud等框架。不同的框架,解决方案不一样。 Springcloud框架,利用lcn来处理分布式事务。利用redis做事务的解决。微服务在每次操作的时候,都需要在redis在存放一个标识符。等全部都完成之后,就提交。 dubbo框架:利用transaction这个中间件来实现分布式事务。还有一种方法就是通过RocketMQ,利用其它的MQ也是可以的。

Hashtable与ConcurrentHashMap的区别

众所周知,Hashtable是安全的,但是效率低下。而ConcurrentHashMap在这两方面都挺好的。这是为什么呢? HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。 HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

ConcurrentHashMap的结构分析

   ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

HashMap的讲解

1.HashMap是基于数组和单向链表的。在这里在解释一下什么是单向链表。就是只有下一个(next),没有上一个。具体的就是总共有(next,key,value,entity)这四个。 2.在这里一定要清楚HashMap怎么存值。他是单向链表,通俗易懂的说就是一个链里套了另一个链。新添的数据总是在最外层。最早的数据都在链表的最里层。 3.还有就是一个扩容,HashMap扩容是根据负载因子决定的。一般负载因子默认是0.75。总数据的长度*0.75就是扩容节点。但在这里一定要记得,并不是肯定到了这个时候都需要扩容。还得根据有没有影响HashMap的整体效率。如果影响了,则扩容。如果没有影响,就不扩容。(拿在这里就要问,怎么样才算应算效率了呢。那么首先得知道,HashMap查询是怎么查的。他是根据数组的链的长度决定的。链的长度越短,效率越高。所以假如有一个数组还为空*****,而其他的数组上链表的长度没有变化,是不影响整个HashMap的效率的)2

HashMap与Hashtable的区别

1.HashMap是不安全的,而Hashtable是安全的。(主要是因为Hashtable每个方法上都有synchronized) 2.HashMap有且允许一个key为null,value可以为多个,而Hashtable里面不可以为null。 3.就是数组的长度不一样。HashMap默认是16,而Hashtable是11。