java面试总结
面试
1、面试指导方针
在面试官问到技术的时候
是什么?有什么特点? what
为什么用它? why
在项目的哪一个地方用过? 使用的具体步骤?使用过程中问题总结? how
2、面试自我介绍之大套路
3、排序算法?
冒泡排序:
每次拿两个数进行比较,总是把小的放在最前面,大的放在最后面,第二次是第二个数和第三个数比较,如果第三个小于第二个,那么第三个和第二个替换位置,一次这样比较替换,第一轮循环完了呢,放在最后面的那个数就是这 一串数字中最大的数。第二轮循环和第一轮一样,第一个和第二个比较,最小的放在最前面,依次类推。如果有10个数字,那么就进行9次循环,最小的在最前面,最大的放在最后面。
好处呢,就是查询速度快
二分查找:
二分查找就是从一串数字中找到某个数字。
原理就是必须有一串数字是从小到大排序,把这串数字进行划分,分为三段,前半段,中止段,和中止后半段。查找数字或者字符先从中止段查找,查到的数字或者字符和中止正好相等,那么久直接取出来,如果比它大就从后半段查找,后半段在进行二分法,进行递归的调用查找,如果比中止小,走前面的中止段,在进行拆分,进行二分查找法。
4、说一下你对Spring的理解?
关于Spring的话,我们平时做项目一直都在用,不管是使用ssh还是使用ssm,都可以整合。Spring里面主要的就三点,也就是核心思想,DI,IOC,AOP。
DI就是依赖注入,把我们需要的类啊,接口啥的注入到spring中去。
IOC控制反转,像我们之前开发,如果想创建一个对象,就new一个,如果想这个对象中定义其他的变量或者对象,就在对象内部创建一个成员变量。但是现在的话,如果想用这个类的对象,咱们可以在spring的配置文件中配置一个bean,指定对应的全路径名称。spring通过配置文件用反射的方式,就可以直接帮我们获取到这个类的对象。但是现在的话,我们还是用注解,方便太多了。
还有AOP,就是面向切面编程,它的原理的话,我看过它的底层代码,它实际上就是实现了JDK的动态代理,以前的话用这个做过事务的控制,现在的话我们都用注解来控制事务。
AOP执行过程是一个纵向的过程,把每个方法当作一个点.基于这些点可以进行增强处理.形成了横向的切面,包含了原有方法和增强方法.不改变原有代码结构,还添加了额外的功能.
平时AOP我们常用来进行事务管理,日志打印(面试题:项目部署后如果监听项目执行状态.)等。
整体来说的话,Spring在使用的时候非常方便,在配置文件中配置要依赖的对象,或者在配置文件中将对象及属性进行注入,当然现在基本都用注解的方式,更方便。
除了这些,我们之前的项目也用过spring的其他产品,像spring boot(简化新Spring应用的初始搭建以及开发过程,用我的话来理解,就是spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架),spring cloud微服务框架。比spring更简单,快速,方便。
(然后就可以扯微服务,和spring boot、cloud)。。。
5、mybatis缓存?
mybatis一级缓存是SqlSession级别的缓存,默认支持一级缓存,不需要在配置文件去配置。
mybaits的二级缓存是mapper范围级别,,除了在SqlMapConfig.xml设置二级缓存的总开关<settingname='cacheEnabled'value='true'/>
,还要在具体的mapper.xml中开启二级缓存:
<mappernamespace='cn.hpu.mybatis.mapper.UserMapper'>
<!-- 开启本mappernamespace下的二级缓存 -->
<cache></cache>
useCache配置禁用二级缓存(默认情况是true,即该sql使用二级缓存。)
<selectid='findOrderListResultMap' resultMap='ordersUserMap' useCache='false'>
mybatis刷新缓存(就是清空缓存flushCache='true' 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新)
<insertid='insertUser' parameterType='cn.itcast.mybatis.po.User' flushCache='true'>
6、说一下Angularjs中常用的指令是什么?
ng-model双向绑定,ng-controller指定模块 ng-app ng-click ng-if ng-init初始化 ng-rpeat
7、简单介绍下分布式
分部式项目就是项目中的模块,把每一个模块拆分成为一个个的工程,这样我们各个模块之间的耦合度不就降低了嘛,然后我们各个模块之间通过dubbo框架来相互通讯,我们公司用到的是一个第三方的插件dubbo来实现项目之间通信,这样我们的代码的拓展性不就更好了嘛,最后我们在部署项目的时候,可以根据用户的访问量来给各个模块的服务器增大配置,我们还可以采用nginx负载均衡来实现一个反向代理,当用户请求后台服务器的时候,有nginx来决定哪台服务器空闲或者压力小,来让用户访问。我们这样做的目的不都是为了防止高并发嘛
8、单例和工厂是如何实现的?
单例:其实单例本质的就是控制对象的产出,要想产生一个唯一的实例,你就要私有化构造方法,然后私有化一个的静态的全局变量,并且提供一个公共的静态的方法供外界访问,单例大概就是这样的。
工厂:它是 java设计模式的一种,工厂模式的优势还是很多的,我举一个简单的共厂的例子吧,就是假如我们有好多接口,好多的接口的实现类,我们如果使用工厂模式的话,当我们有需求需要改变接口的实现类的话,直接在工厂里面改变返回的类型就好。这样会应对不同的需求变化。
9、MyBatis中# 和 $ 的区别?
这两个符号一般是在使用Mybatis编写底层SQL语句时使用,#就是一个占位符,具体的使用是#{id},而$是一个原样输出的标识,是${value},我在项目里一直是使用#,因为这样可以防止Sql注入,安全性高。
10、Hashmap的底层实现原理
Hashmap底层是通过数组和链接联合实现的,当我们创建hashmap时会先创建一个数组,当我们用put方法存数据时,先根据key的hashcode值计算出hash值,然后用这个哈希值确定在数组中的位置,再把value值放进去,如果这个位置本来没放东西,就会直接放进去,如果之前就有,就会生成一个链表,把新放入的值放在头部,当用get方法取值时,会先根据key的hashcode值计算出hash值,确定位置,再根据equals方法从该位置上的链表中取出该value值。
11、简单说一下ssm 整合?
答:简单的说 springMVC在ssm中整合 就是 在 web.xml 里边配置springMVC的核心控制器:DispatcherServlet; 它就是对指定后缀进行拦截;然后在springMVC.xml里边配置扫描器,可以扫描到带@controller注解的这些类,现在用springMVC都是基与注解式开发, 像@service,@Repository @requestmapping,@responsebody 啦这些注解标签 等等 都是开发时用的,每个注解标签都有自己的作用;它还配置一个视图解析器,主要就是对处理之后的跳转进行统一配置 ,大致就是这些
12、Mybatis 和 Hibernate 的区别
Hibernate一个是全封装,mybatis是半封装,使用hibernate做单表查询操作的时候比较简单(因为hibernate是针对对象进行操作的),但是多表查询起来就比较繁琐了,比如说5张表10张表做关联查询,就算是有SQLquery那后续的维护工作也比较麻烦,还有就是Hibernate在Sql优化上执行效率上会远低于MyBatis(因为hibernate会把表中所有的字段查询出来,比较消耗性能)我们以前在做传统项目方面用过hibernate,但是现在基本上都在用mybatis.
13、为什么要离职?
.
14、给我介绍一下dubbo吧
dubbo是一个分布式架构的服务框架,一般结合maven的模块开发使用。传统的单架构项目,不方便维护和升级;通过maven的模块式开发,就可以把一个单架构的工程,拆封成一个一个的小模块,包括(jar和war);jar包可以被war包直接应用。war包可以分布式部署,但是这样不同的war之间的交互就成为了问题。我们之前的做法是,两个war之间进行交互时,一般采用webservice或httpclient。但是在这种分布式架构中,多个war之间的交互会特别频繁,如果用webservice或httpclient架构师很多时候自己都搞不清楚他们之间的依赖关系了。而dubbo解决了这个问题,有了dubbo架构以后,多个war之间不在直接进行交互,而是统一和dubbo的注册中心zookeeper进行交互。无论是发布服务还是调用服务,都通过dubbo实现,并且提供了web页面,来监控和管理各个接口直接的调用。
使用时首先搭建dubbo的注册中心zookeeper,然后下载dubbo的服务治理工程dubbo_admin.war,解压修改他的配置文件dubbo.properties,设置用户名、密码和注册中心zookeeper的ip、端口。部署到Tomcat的webapp中,启动Tomcat,浏览器用ip+端口访问,就可以看到dubbo_admin的web页面了。接着在我们要发布或者调用服务的项目中,导入dubbo提供的相关jar包,加载配置文件,把要发布的服务注册到zookeeper里边。或者从zookeeper里边调用服务就可以了。dubbo_admin的web页面中,可以监控和管理所有的服务提供者和调用者。。
在dubbo架构中,service接口和实体对象时各个工程共享的,service实现类是发布服务的工程独有的。只需要发布服务的工程把他的接口注册到zookeeper中,其他工程就可以从zookeeper中进行调用了。
用dubbo的好处是:把项目拆分成各个独立的小工程,通过接口调用方式,互相交互数据,可以单独进行部署和升级,这样就减少了他们直接的耦合性和代码的复用性。还可以针对不同模块采用不同的部署策略,比如订单模块并发比较高,所以可以把订单模块这个war包,单独部署多套,都注册到同一个zookeeper中。当客户端调用时,zookeeper会帮忙进行负载处理。
15、说一下springaop的实现原理
答:它的底层是通过动态代理实现的面向切面编程,主要用在管理事物这一块,我们在配置文件里配置切入点,比如以save/insert/update等开头的方法我们开启事物,配置了一个REQUIRED开头的事物特性,还可以用在日志管理,还有权限方面也可以用aop来实现,但现在基本上没有人去这样控制权限,都用shiro框架来实现权限管理,springaop大概就是这样,咱们公司是用什么来管理事物的,应该使用注解的方式来管理的吧。
16、说一下什么事务?代码中事务是如何控制的?
在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交,多表操作的时候会用到事务,我们在项目中直接配置到spring里就用啦,用的注解式的事务,比如说银行转账,从A账户向B账户转账,必须得两条SQL语句同时执行成功.
Java中的事务主要有两种,JDBC事务(本地事物)和JTA(Java Transaction API)事务(分布式事物);事务有四大特性ACID原子性、一致性、隔离性和持久性。框架中,我们一般把事物交给spring来管理。spring配置事务的方式一般有两种,一个是声明式事务,一个是注解式事务。注解事务,比较简单灵活,在spring配置文件中配置一个<tx:annotation-driven> 饿里忒甚的注解,然后在需要的方法上加@Transactional注解就可以了。声明式事务,切点一般是扫描service层实现类,通过方法名匹配配置传播特性,决定哪些方法上加事务,哪些不需要事物。事务主要有五大隔离级别和7种传播特性;五大隔离级别由低到高:主要控制是否出现脏读,不可重复读和幻觉读;7种传播特性主要决定是新建事务,还是取当前事务;
脏读:
指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
不可重复读:
指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻觉读:
指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户
事物主要是为了保证一次操作里边涉及到多次增删改时,保证他们可以同步提交或回滚。他有四大特性ACID(原子性、一致性、隔离性、持久性)
原子性(Atomicity):事务是数据库逻辑工作单元,事务中包含的操作要么都执行成功,要么都执行失败。
一致性(Consistency):事务执行的结果必须是使数据库数据从一个一致性状态变到另外一种一致性状态。当事务执行成功后就说数据库处于一致性状态。如果在执行过程中发生错误,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这是数据库就处于不一致状态。
隔离性(Isolation):一个事务的执行过程中不能影响到其他事务的执行,即一个事务内部的操作及使用的数据对其他事务是隔离的,并发执行各个事务之间无不干扰。
持续性(Durability):即一个事务执一旦提交,它对数据库数据的改变是永久性的。之后的其它操作不应该对其执行结果有任何影响。
我们框架中一般都通过Spring的AOP去管理事物;常用两种有方式:声明式事物和注解式事物;
声明式事物就是通过在配置里边配置他的事物传播特性和切入点的方式实现;切入点我们一般扫描所有的service层的方法做为切入点;事物传播特性一般通过方法名称判断去使用只读事物还是可增删改事物;
注解式事物:在Spring配置文件里边开启以后,在需要事物增删改事物的方法上加上@Transactional注解就可以了;
事务的隔离级别也分为四种,四个级别可以逐个解决脏读、不可重复读、幻读这几类问题
7种事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播
18、如何解决高并发?
我在公司的时候,都是通过solr全文检索、redis缓存,还有使用高性能的服务器、高性能的数据库、高效率的编程语言、高性能的Web容器等等来解决高并发的问题。
19、什么是微服务?为什么使用微服务
微服务就是一种分布式的架构
把项目中的每一个模块采用单独的业务逻辑封装,每个项目都可以独立部署和扩展,服务之间可以通过springCloud的Eureka组件作为注册中心使用Feign组件进行服务间的互相通信,我个人认为使用了微服务架构可以降低我们代码的耦合度,在开发的时候,比较好分配项目,还有就是后期再进行项目功能扩展的时候也比较灵活.
20、如何使用Spring Boot实现分页和排序?
使用Spring Boot实现分页非常简单。使用Spring Data-JPA可以实现将可分页的org.springframework.data.domain.Pageable传递给存储库方法。
21、图片是怎么存储的?
用的是FastDFS文件服务器,FastDFS架构包括一个Tracker server 和一个 Storage server 。
客户端请求Tracker server 进行文件上传、下载,通过Tracker server 调用Storage server完成文件上传和下载。
Tracker server可以完成负载均衡,它其实是这样的,这个Storage server 会定时的向tracker server 发送自己的状态,tracker server就能知道那个storage server是空闲还是忙碌,当上传下载的时候,就会调用空闲的storage server ,当上传或下载的时候,这个storage server会生成filed id ,并将文件写到磁盘,返回一个路径信息和文件名,拿到路径信息我们就可以存到数据库或调用了。
22、Spring常用的注解
1、@Component
是所有受Spring 管理组件的通用形式,@Component注解可以放在类的头上,@Component不推荐使用。标注一个普通的spring Bean类。
2、@Controller对应表现层的Bean。标注一个控制器组件类。
3、@Service对应的是业务层Bean。标注一个业务逻辑组件类。
4、@Repository对应数据访问层Bean。标注一个DAO组件类。
在spring未来的版本中,@Controller,@Service,@Repository会携带更多语义。尽量考虑使用@Controller,@Service,@Repository代替通用的@Component。
5、@Transactional 应用事务的注解
1)定义到方法上: 当前方法应用spring的声明式事务
2)定义到类上: 当前类的所有的方法都应用Spring声明式事务管理;
3)定义到父类上: 当执行父类的方法时候应用事务。
在spring未来的版本中,@Controller,@Service,@Repository会携带更多语义。 尽量考虑使用@Controller,@Service,@Repository代替通用的@Component。
23、公司有技术分享吗?
当然有啦,我们公司每周五的下午都会有一个小组做技术分享,分享一个技术,或者我们项目当中相关的新的业务,如遇到了什么问题,是怎么解决的。最新技术的分享 ,像springboot 微服务,分布式事务啦等等,他会问分布式事务,照着后面的说
24、你们项目中事务是怎么配置的?
首先配置事物的管理器定义属性声明事物规则定义切面
然后将事物增强与切面组合
最后开启事物注解标注
Transaction的类和方法将具有事物
25、线程之间可以共享内存吗?
可以。在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信息量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
不同进程之间共享内存通常安排在同一段物理内存中,进程可以将同一段共享内存连接到他们自己的地址空间中 如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
共享内存并未提供同步机制,就是说 在第一个进程结束对共享内存的写操作之前 并没有自动机制可以阻止第二个进程开始对它进行读取,使用我们通常需要用其他的机制来同步对共享内存的访问。
26、session和cookie 区别
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
cookie数据存放在客户的浏览器上,session数据放在服务器上。
cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
27、给我讲一下ActiveMQ这个技术
(What ActiveMQ是什么?)
先说jms规范
讲这个ActiveMQ,需要先聊到java中有一个JMS规范,就是java 消息服务规范,这套规范包含点对点,订阅两种方式来收发消息,简单来说的话,就是JMS制定了这样一个规范,里边的API与具体的平台无关。
ActiveMQ是支持JMS规范的一个开源技术,它支持好多通讯协议,像我们最常用的TCP和UDP,它都支持,activeMQ支持多种通讯协议TCP/UDP等。对于TCP协议,我们知道TCP有一个三次握手,所谓的三次握手可以这样来理解,比如A和B建立连接时,首先A向B发出一个同步请求,然后B回复一个同步请求应答,最后A回复一个确认信息。
ActiveMQ消息如何发送接收
就拿ActiveMQ中所支持的TCP协议来说,ActiveMQ初始化时,通过类根据配置打开TCP侦听端口,客户通过该端口发起建立链接的动作。 生产者发送一个消息,进入到消息队列中,然后消费者可以从队列中取出消息
在ActiveMQ中分为生产者和消费者,生产者发送消息,消费者接受消息,里边有一个比较重要的机制叫做消息中转器,它是activeMQ的核心,消息会先经过中转器,然后再分发给消费者
发送消息方式
对于ActiveMQ发送消息的方式,是分为两种的,其实它也是符合JMS规范的,就是点对点和订阅消息类型,对于点对点,每个消息只能有一个消费者,这种方式是基于队列的,如果消息不被消费,就会一直阻塞在队列中,只有当消费者消费之后消息才会消失。
对于订阅方式,它是基于主题topic的,可以有多个消费者,类似于广播,只要你订阅了,就能够收到这个消息,如果发的时候还没启动消费者,那这个消息就会被错过。
心跳机制
还有这个ActiveMQ还有一个心跳的机制,这种机制可以判断收发双方链路是否通畅,它内部使用的机制是双向心跳,也就是ActiveMQ的生产者和消费者都进行相互心跳。心跳这里会产生两个线程,一个是“ReadCheck”“WriteCheck”,它们都是timer类型,每隔一段时间都会被调用一次.
其实这个ActiveMQ的信息还是挺多的,比如它发送消息能实现即时发送,还能实现定时,延时发送.
28、ActiveMQ原理
ActiveMQ收发消息的原理和具体流程大约是这样的:
发送方:
创建一个连接消息中转服务器的连接工厂。
根据这个工厂获取到一个具体的connection
启动连接,创建session回话
设置发送消息的类型,可以指定topic也可以指定点对点
将消息发送出去
消费方:
也是创建一个连接消息中转服务器的连接工厂
根据这个工厂获取到一个具体的connection
启动连接,创建session会话
定义消息消费者,准备接收消息
设置一个消息接收的监听者,当有消息回调接收到的时候,回调到onMessage方法中
(Why为什么使用ActiveMQ)
我们做的项目由于是分布式项目,各个模块之间都是相互独立的,就会有这样的需求,比如模块之间的通信问题,或者高并发,就会用到消息队列,消息队列的话,常用的有RabbitMQ,ActiveMQ,阿里的RocketMQ,rabbitmq支持的协议比较多,是一种重量级的消息框架,阿里的rocketmq没有用过,我们常用的是activeMQ,属于轻量级的。
(How ActiveMQ怎么用)
使用场景
对于ActiveMQ在我们开发中,主要应用到这么几个场景,比如,我们的项目现在都是分布式的,咱们不可能在一个模块中实现所有的功能,就拿商品管理模块来说,当对商品做添加,修改,删除操作时,其他模块也有可能有相关连的变化,比如前台模块中的搜索,商品信息变了,索引库中内容也应该有相应的变化,这个时候呢,我们就需要用到一个通信机制,那ActiveMQ这种类型的框架我们就恰好需要的,可以在商品操作时,发送一个消息说我商品信息改变了,当然需要指明哪一个商品发生了变化,发送对应的商品id就行,在前台模块中,我们配置一个消息接收端,当接收到消息时,对索引库做下修改就行。
当然,除了商品添加同步更新索引库,像商品详情模块,在商品审核通过以后,想消息队列中发送了一个商品id到消息队列中,pageService工程中有一个监听类,可以生成相应的静态页面,,还有订单模块也有用到过,当执行生成订单,进行银行扣款,扣款成功,减库存啊,这种类型的操作,都可以通过ActiveMQ发生消息来实行同步操作。
具体操作
以上呢,是介绍一下ActiveMQ,对于ActiveMQ的使用,我们是这样来做的
,拷贝一个ActiveMQ压缩包放到在Linux服务器上,解压,用./activemq启动activemq,这个就是我刚才所说的消息中转服务器,我们还可以访问一个管理界面,能够查看收发消息的状态。
在maven项目,我们需要在pom文件中配置activemq的jar包信息
在发送端的springmvc的配置文件中配置mq的连接工厂,指定消息服务器的ip端口,配置Spring提供的JMS模板类工具类(jmsTemplate),配置发送消息的类型。在需要进行发送的代码逻辑中,直接使用spring提供的模板类 jmsTemplate.send就可以了,至于发送的内容,可以自己指定。是文本类型,还是消息对象消息,按需求指定就可以。
同样的,在Springmvc配置工厂,服务ip端口,还需要额外指定一个监听器,这个监听器就是自己定义的一个类,实现MessageListener ,当收到消息时,就会触发里边的一个回调方法,把消息取出来,执行相应逻辑就可以。
29、非关系型的数据库; ( redis )Redis的运行原理,在哪个模块用,有没有出现什么问题(话术总结)
Redis是一个非关系型的数据库,以key-value的形式存储在内存中的,
存储的数据类型有字符串,列表类型还有散列表型,项目中常用string和hash这两种类型;redis还可以将数存储到磁盘中,
有两种形式rdb和aof两种,
rdb是以快照的形式来存储数据的,
redis默认也是这种存储形式,性能较好
aof是即时存储,每个一秒存储一次,性能比较差;
在项目中,网站的门户访问量很高,所以其中的大广告位商品的展示用到了redis缓存,以提高用户的体验度,还有单点登录也用到了redis缓存,用户登录时生成一个不会重复的token,以此为key值,用户的信息为value值,来存储数据,并且通过cookie把taken返回给浏览器,访问其他模块是就可以从redis中取出用户的信息
Reids存在的问题就是内存中的数据还没有保存到磁盘上时,服务器宕机或者断电,就会发生数据丢失,
解决的途径是提高存储的频率。
30、给我介绍一下redis
Redis是一个继memcached后的又一个第三方缓存数据库,他比memcached强大很多,支持更多的数据类,它作为数据库和应用程序直接的中间层来使用,已减轻数据库压力,提高运行效率。
我们项目中很多地方用到了redis;比如商品的三级分类、省市县、关于我们、联系我们、友情链接,常见问题等经常查询但是不经常改变的数据.redis还可以在tomcat集群里边实现session的共享。由于他的单线程的,所以在电商平台里边也经常用他做“防止超卖”, 生成规则的商品编号等。还有就是购物车也用到了redis
代码中,我们一般都通过spring整合redis官方提供的jedis工具包来操作redis。可以是单机版,也可以是集群。Redis本身就支持集群操作redis_cluster,另外redis还支持主从复杂,还有他独特的哨兵模式,在主服务器宕机时,从服务器可以自动转换为主服务器。另外,他也有他的分片机制,就像mysql的水平分表设计,数据量大时,可以把数据存储到不同的库中,来减轻redis负担。
Redis的持久化方式主要有2种,RDB和AOF,RDB是一种快照方式,默认每隔5分钟创建一个快照副本,这种方式占用空间大,而且会丢失间隔时间5分钟之内的数据,但是他适合做备份,恢复时,可以根据需要恢复任意间隔时间点的数据。AOF是一种日志的持久化记录方式,每秒钟,都把redis中新增的数据记录到日志文件中,这种方式只有一个文件,占用空间少,最多丢失1秒内的数据。相对比较好,但是如果想要恢复5分钟或10分钟前某个时间点的数据,就不行了。所以实际项目中,我们一般会两种方式同时使用。如果搭建集群的话,还可以通过集群互相备份数据,只要集群不同时挂掉,单个redis就可以从集群中的其他服务器获取到最新数据。
还有就是,由于redis不是很稳定,有时候会发生“穿透”和“雪崩”; redis,都是按照key去缓存查询,如果不存在对应的value,就应该去数据库查找。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力,这就叫“缓存雪崩”。解决办法是,对查询结果为空的情况也进行缓存,并且给缓存设置不同的有效期。当然redis容灾的最有效的方法还是搭建集群。在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
快照(RDB)方式,默认方式,文件以二进制方式保存到RDB文件。
文件追加(AOF)方式,文件以协议文本的方式write到AOF文件。
作用,重启后的数据恢复。当两种方式都启用时,redis会优先载入AOF文件,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
注意优先是指载入AOF文件就不再加载RDB了,不管AOF是不是空文件。
5. Redis和memcached的区别
1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;redis支持事务
3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘;
4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10;
5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从;
6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);
7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;
8、Redis支持数据的备份,即master-slave模式的数据备份;
9、应用场景不一样:Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等。
31、redis的数据类型?
我了解的有
字符串类型、
list,我们可以向list的两端添加数据
集合set,存放的数据是无序的,集合中的数据是不重复的,由于它是无序的,所以不能通过下标来获取制定元素、
order set有序集合、
hash
实际上我们常用的也就是string 和hash
redis是通过key-value存储的 set key value string
hset key value hget key value
32、redis的持久化方案有哪些
答案:RDB,AOF俩种,RDB是一种快照的方式来存储的,这也是redis的默认的持久化方式,每隔一段对数据进行一次存储,默认是15S。
AOF是即时性的持久化方式,这种方式对数据的保存完整性比较高,但是性能比较差。
而RDB存在的问题主要是服务器宕机或者断电,就会造成数据丢失,我们可以适当的把存储间隔缩短一些
33、平常用什么开发工具
IDEA,Eclipse,MyEclipse,数据库操作用nvacat或者sqlyong,还有数据库建模用powerDesner
34、Redis是如何同步的?
读取数据的时候先从redis里面查,若没有,再去数据库查,同时写到redis里面,并且要设置失效时间。存数据的时候要具体情况具体分析,可以选择同时插到数据库和redis(要是存放到redis中,最好设置失效时间),也可以选择直接插到数据库里面,少考虑一些问题,添加内容的,把对应的redis里的数据的删除掉.第一个人查的时候从数据库里查询,把数据放到的缓存中,第二个人访问就可以直接从缓存中访问数据了
35、java arrayList的存储结构,初始化的时候创建多大的数组?
ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。
讲一下solr吧
Solr是一个基于Lucene开发的全文搜索引擎,项目中一般用它做首页的全文搜索或者做文件管理系统中的文件检索,因为他提供了分词的支持,同时采用文件存储数据,所以无论是查询速度还是匹配精确度方面,都比数据库的like查询方便了很多。比如:电商网站上,用户想买手机,输入“苹果手机”,但是系统中录入的是ipone手机,那么用like查询就很难匹配到,但lucene就可以解决这个问题。
使用时,Lucene官方紧紧提供了核心实现的jar包,我们只能通过api文档,自己实现创建索引和查询的逻辑,并进行优化处理,开发比较繁琐,但比较基础,更灵活,做文档的检索时可能相对更好点。而solr是Apache开发的一个开源的web工程,他帮我们实现了创建索引、查询等操作,经内部进行了一定的优化,然后以restful风格对外提供了接口。并且提供了solrj的sdk工具包,方便Java开发者直接使用。一般做电商等网站的全文搜索,我们使用时,只需要官方下载到solr工程的war包,根据我们的实际情况,修改solrhome 、solrconfig.xml和schema.xm文件,简单配置一下使用的数据库和创建索引的sql和字段,然后把war包进行部署就可以了。可以通过他提供的页面进行创建和查询索引的操作。也可以在项目中集成solrj的jar包,直接调用他的方法,进行创建索引和查询的操作。
Solr支持高亮显示搜索关键字,支持匹配权重配比(无特殊排序要求时,默认根据查询相关度来进行排序,可以在配置文件中配置,通过权重配置相关度) 、支持分页,支持自动分词等。我们一般都采用IK分词器,代替他默认的标准分词器。因为IK对中文的支持比较好。如果想要支持拼音,还可以使用它的拼音分词器。Solr也支持集群部署,官方提供了SolrCloud的部署方案,一般通过solrcloud+zookeeper实现,zookeeper在solr集群中主要有两大作用:1负载均衡2集中式配置管理。需要注意的是:zookeeper一般采用选举机制,所以一般都是2n+1(奇数)台。
另外由于solr查询时,不是直接查询数据库,而是开始时,先把数据库中的数据同步到索引文件中,查询时,直接查询索引文件。索引数据库数据修改时,需要同时同步到solr的索引文件中,也就是创建索引。创建索引分为全量创建和增量创建。可以通过配置文件实现自动增量更新,自动增量更新可定时将数据库中的数据导入到solr索引库中,并可定时重建索引库,合并小索引文件为大的索引文件。除了solr以外,最近又出了一个搜索引擎叫ElasticSearch,我简单了解了一下,他和solr一样,也是一个基于Lucene的,rest风格的,分布式搜索引擎。Solr特点是:查询快,但更新索引时慢(即插入删除慢),对用于电商等提前录入好数据,之后查询特别多的应用;而ElasticSearch简称ES建立索引快、查询相对慢点,但综合上表现为实时性查询快,用于新浪了,facebook了等搜索。
zookerpper的作用 动物园管理员;
配置管理。名字服务,集群管理
solr、Lucene、es的区别;
Lucene是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构
3、solr集群搭建主要步骤,和集群方案;
4、solr高亮和分页
高亮显示查出的字段和高亮的颜色大小啥的 分页是先获得条数 还有除以条数 的到页数
5、solr权重配置;
6、索引创建;全局索引和增量索引;
7、solr部署主要步骤;
8、solrhome
9、solrconfig.xml,主要定义solr的处理程序(handler)和一些扩展程序;
solrconfig.xml 文件不仅指定了 Solr 如何处理索引、突出显示、分类、搜索以及其他请求,还指定了用于指定缓存的处理方法的属性,以及用于指定 Lucene 管理索引的方法的属性。
10、schema.xml,主要定义索引的字段和字段类型。
fieldtype、Fields、copyField、dynamicField
39、java中的泛型有哪些,为什么要用(需要整理)
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。
限制性:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");
简单介绍:
在Java 5之前,为了让类有通用性,往往将参数类型、返回类型设置为Object类型,当获取这些返回类型来使用时候,必须将其“强制”转换为原有的类型或者接口,然后才可以调用对象上的方法,强制类型转换很麻烦,我还要事先知道各个Object具体类型是什么,才能做出正确转换。否则,要是转换的类型不对,比如将“Hello Generics!”字符串强制转换为Double,那么编译的时候不会报错,可是运行的时候就挂了。那有没有不强制转换的办法----有,改用 Java5泛型来实现。
40、全外连接 左右外连接 内链接相同条件下 查询数据数量比较
全>左右>内
内联接(INNER JOIN)
仅将两个表中满足连接条件的行组合起来作为结果集。在内连接中,只有在两个表中匹配的行才能在结果集中出现
左外连接(LEFT JOIN)
左表的所有数据和右表符合条件的数据
右连接相对应 (RIGHT JOIN)
全外连接 (FULL JOIN)
返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列用null代替。如果表之间有匹配行,则整个结果集行包含基表的数据值。
41、fastDFS下载
文件上传后返回一个路径信息和文件名,拿到路径信息我们就可以存到数据库或调用了。
42、感觉在开发中比较有成就的项目
我比较有成就感的项目是一个手机APP 叫 小象优品
它是一款以网络购物为核心业务的app,一共分为两大模块,分别是客户端和后台管理系统。
它的客户端有商品搜索,商品展示,购物车,支付等这些功能,对于客户来说,可以浏览并找到自己满意的商品,这样客户会获得便捷的购物方式和放心的服务。
而后台管理系统 有用户管理,商品管理,订单管理,店铺管理等功能,对于卖家来说可以通过简单的操作,就能实现商品的售卖和管理,非常大的便捷,简单;
我主要负责商品模块,包括搜索商品和商品的展示。
我主要用到的技术有solr ,它实现所有商品的搜索功能,Solr它是一个全文检索服务器,我们可以通过solr 设置 条件查询,还有 高亮显示啦 这些功能,现在不是都用solr来做嘛,它的查询效率是比较高的; ,我还使用ActiveMQ这个消息队列 它可以实现索引库和缓存的同步,比如我们做商品添加时,用activeMQ可以把数据同步到solr上,还搭建了nginx+FastDFS服务器来管理我们项目中图片和文件的上传及下载;
43、消息队列activeMQ怎么使用的?
acticeMQ是消息队列的一种,(RackMQ,阿里的消息队列,这种消息队列听过没用过,)在解决solr搜索时实现消息同步采用的方法,像解决添加商品的时候,往solr索引库中添加一条记录这种情况下使用(当然,像增删改这些都适用),在项目里我是这样使用的,先搭建一个activeMQ服务(从apache官网上下载资源),引入相关的jar包,在添加商品的jar包工程里(分布式开发)配置一个activeMQ的配置文件,配置到spring的配置文件中,当发生商品添加时,发送一个商品的id到activeMQ上,在搜索服务的war包工程里在配置一个activeMQ的配置文件,在里面设置监听,(拓展:activeMQ发布服务的方式为点对点式Queue和发布订阅式Topic,采用的是订阅式发布Topic(订阅发布式)发布的服务没有消费者消费的情况下是不会在服务器端进行缓存的,直接就会找不到了,但是Queue(点对点)这种模式如果消费端没有消费的话,是直都会保存到服务器端的.)当发生商品添加动作 时,会从activeMq中获取到商品id,在监听的类中调用相关的接口和方法向索引库里面添加相关的信息,从而实现同步的功能。
44、你们公司的接口是怎么管理的?
那个接口开发,我们就是这么做的,就是用的那个springMVC结合swgger来做的那个接口开发,swgger提供一些注解,可以把接口文档通过网页的形式可以展示出来,上面能标清楚他的url,参数,返回类型什么的,比较方便,原来我们没有用swgger的时候,用的都是那个word文档,但是用容易丢,不好维护,后来才用的swgger,现在同类型的产品也挺多的,我们公司反正用的都是swgger。
45、简单说一下sql语句是怎么优化的
(01)选择最有效率的表名顺序(笔试常考) 数据库的解析器按照从右到左的顺序处理FROM子句中的表名, FROM子句中写在最后的表将被最先处理, 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后, 如果有3个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。1)如果三个表是完全无关系的话,将记录和列名最少的表,写在最后,然后依次类推 2)如果三个表是有关系的话,将引用最多的表,放在最后,然后依次类推
(02)WHERE子句中的连接顺序(笔试常考) 数据库采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之左, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的之右。
(04)用TRUNCATE替代DELETE
(05)尽量多使用COMMIT 因为COMMIT会释放回滚点
(06)用WHERE子句替换HAVING子句 WHERE先执行,HAVING后执行
(07)多使用内部函数提高SQL效率
(08)使用表的别名
46、pc端和app是不是共享一个接口,为什么
一般得看需求因为controller不是一个的有可能pc端的是返回页面移动端的是返回json数据格式根据实际的需求而定
47、跨域是怎么解决的
跨域这块呢,之前我们用过JSONP来解决跨域问题,现在项目用到springMVC了,它里边有个@CrossOrigin(origins="http://localhost:9105",allowCredentials="true")
开发时侯跨域调用这块还用到过HttpClient这个技术,把它放到工具类里变用的时候直接调用就行了,项目开发中也用到过一些其他这样的技术,像遇到C语言向java语言这种跨语言的通信,就用到WebService技术,它的底层通信用的是soap协议,用的是cxf方式来发送的。
48、jdk1.8 和1.7区别
JDK1.8的新特性
一、接口的默认方法
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用
default关键字即可,这个特征又叫做扩展方法。
二、Lambda 表达式
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,
Java 8提供了更简洁的语法,lambda表达式:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
三、函数式接口
Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式
都对应一个类型,通常是接口类型。而“函数式接口”
是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式
都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,
所以你也可以给你的函数式接口添加默认方法。
四、方法与构造函数引用
Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,
上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:
converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);
五、Lambda 作用域
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。
你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
六、访问局部变量
可以直接在lambda表达式中访问外层的局部变量:
七、访问对象字段与静态变量
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。
该行为和匿名对象是一致的:
八、访问接口的默认方法
JDK 1.8 API包含了很多内建的函数式接口,在老Java中常用到的比如Comparator
或者Runnable接口,这些接口都增加了@FunctionalInterface注解以便能
用在lambda上。
49、用户注册怎么知道谁有URL权限
给不同类型的用户设置不同的状态码,通过状态码匹配角色表,再通过角色表匹配权限表 从而实现URL权限赋予功能
50、全文检索谁来定?
由业务来定。比如说做商品检索时,时搜索商品的名称,卖点,描述。以这些业务域进行所搜的
51、购物车模块cookie被禁止了,怎么解决?
URL重写,对所有页面涉及的连接都使用url重写方式。从而将JsessionID
以参数的方式链接到URL后面。保证每次页面提交时服务器都能获得sessionID从而维持和客户端的状态。
52、关于统计的sql语句?
count max min sum avg
53、js中的==和===的区别?
”==”与”===”是不同的,前者是判断值是否相等,后者是判断值及类型是否完全相等。
54、事务的传播特性?
1.PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
2.PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
3.PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
5.PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。
55、在开发的时候设计过哪些文档,有什么规范吗?
传统方式: 接口文档三要素:URL 、参数、返回值
需求文档: 客户做需求调研的时候写过,根据客户的需求我们来写文档。画流程图、写开发步骤、主要功能点的介绍等
系统设计:有哪些功能点、规定了具体方法、类、字段,涉及数据库表、字段,后期编码
互联网项目:采用敏捷式开发,利用swagger设计文档,生成文档的URL、参数、返回类型。
说一下FreeMarker这个技术吧
freemarker是一个模板化引擎语言,传统项目中,后台页面基本上都是list列表,页面都是类似的,只是展示的数据不一样。这样我们就可以把他的样式做成一个freemarker模板,然后传入数据就可以展示不同的页面。他的模板一般是以.ftl结尾的。如果使用这个呢,可以使我们开发人员不需要太关注前台。但是对于很多门户或商城类项目,每个页面都是不一样,所以用他也不是很方便。另外,由于可以把freemarker模板直接转换成html、jsp、java、xml、word等各种文档。所以我们经常使用他做代码生成、word生成或者首页静态化等。我这里就用到了首页静态化的功能。由于任何用户访问时,首先会访问到我们的首页,所以很多东西都希望能在首页展示,但是放的东西多了,就会加载很慢。给用户的体验度很不好。所以我们在项目启动时,直接把首页需要的数据查询出来,通过freemarker模板生成静态的html页面,之后用户访问时,都去访问这个静态页面,这样就不需要频繁访问数据库,减轻了数据库压力,提高了用户体验度。但是缺点是,数据库数据数据变换了以后,数据无法实时更新。我们一般通过定时器的方式,每天凌晨重新生成。
还有就是热销商品的商品详情页面也做了静态化处理,首页我们是通过定时器每天凌晨一点,去重新生成;商品详情我们是在商品信息修改以后,给定时器表(id,业务id、type,remark)中推送一条信息,到第二天凌晨一点时,定时任务扫描表,发现有需要重新生成的页面,就调用freemarker模板,重新生成html页面,以商品id作为html页面名称,然后删除任务表中的数据。为了预防大量静态页面给服务器造成压力,我们把html页面直接生成到Nginx的静态页面服务器上。访问时,不用经过Tomcat,直接通过Nginx访问。
57、有一个新的页面(或者模块)让你开发,需要多长时间:
您能给我说一说这页面或者模块要实现的功能,它要实现什么样的效果,还有它的需求文档等等一些资料,这样我才能根据这些资料,来大致算一算要多长时间能完成。
58、Spu和Sku分别是什么意思?
sKU是库存量单位,区分单品,.另外还有SPU,是标准化的产品单元,区分品种,
例如 iphon8这是一个SPU 苹果8 (64G 黑色 移动) 这就是一个SKU.
59、你们solr有专门的地方维护吗?是手动添加还是?(同步问题)
我们用的是SpringDataSolr来操作的Solr索引库.
我们项目在第一次上线的时候,会手动往solr索引库导入一批数据,后期就不用人工干预了,我们后台添加了相应的商品之后,商品审核通过的时候,用的ActiveMQ往里面发送一条消息,商品的ID,然后在solr这个search这个工程中,我们会接收到这个id,然后把这个id从数据库里面查询出来该商品信息,把数据添加到我们的索引库里边去。维护大概就是这样。
60、项目中的管理工具用的什么
你是说的项目版本管理,还是项目进度管理,我们项目版本管理用的是SVN,我们项目进度管理项目经理用的是禅道,还有那个project软件管理的进度.
61、项目中用的什么做的压力测试
LoadRunner: 是Windows系统下的一个测试工具。是一种预测系统行为和性能的负载测试工具。通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner能够对整个企业架构进行测试。企业使用LoadRunner能最大限度地缩短测试时间,优化性能和加速应用系统的发布周期。 LoadRunner可适用于各种体系架构的自动负载测试,能预测系统行为并评估系统性能
62、项目当中的多线程,线程池是怎么回事
项目中的多线程,线程池是怎么回事
多线程:解决多任务同时执行的需求,合理使用CPU资源。多线程的运行是根据CPU切换完成,如何切换由CPU决定,因此多线程运行具有不确定性。
线程池:现在服务器端的应用程序几乎都采用了“线程池”技术,这主要是为了提高系统效率。因为如果服务器对应每一个请求就创建一个线程的话,在很短的一段时间内就会产生很多创建和销毁线程动作,导致服务器在创建和销毁线程上花费的时间和消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。线程池就是为了尽量减少这种情况的发生。(适用于短时间内多任务的情况,如果线程执行时间较长不适用线程池)
63、什么是死锁
打个比方,假设有P1和P2两个进程,都需要A和B两个资源,现在P1持有A等待B资源,而P2持有B等待A资源,两个都等待另一个资源而不肯释放资源,就这样无限等待中,这就形成死锁,这也是死锁的一种情况。给死锁下个定义,如果一组进程中每一个进程都在等待仅由该组进程中的其他进程才能引发的事件,那么该组进程是死锁的。
竞争不可抢占资源引起死锁
也就是我们说的第一种情况,而这都在等待对方占有的不可抢占的资源。
64、死锁的发生必须具备4个条件
互斥条件: 其实就是进程对所分配到的资源进行排它性使用,是指在一段时间内某个资源只能由一个进程占用。如果此时还有其它进程请求资源,那么其它线程只能等待,直到占有资源的进程用完被释放掉。
请求和保持条件: 指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
不剥夺条件: 指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
环路等待条件: 指在发生死锁时候,一定存在一个进程相当于资源的环形链,也就是进程的集合像{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源
65、如何避免死锁四种方法
(1) 检测死锁
这种方法并不须事先采取任何限制性措施,也不必检查系统是否已经进入不安全区,此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源,然后采取适当措施,从系统中将已发生的死锁清除掉。
(2) 解除死锁。
这是与检测死锁相配套的一种措施。当检测到系统中已发生死锁时,须将进程从死锁状态中解脱出来。常用的实施方法是撤销或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,以继续运行。死锁的检测和解除措施,有可能使系统获得较好的资源利用率和吞吐量,但在实现上难度也最大。
66、IO和NIO的区别?
它们的主要区别是:io 是面向流,阻塞io,而nio是面向缓冲,非阻塞的io;
io的话每次从流中读取一个或多个字节,直到读取完所有的字节,没有缓存到任何地方.nio读取的是数据是有缓存,就是说他读取的数据是在缓冲里读的.
另外的话,java中的各种io是阻塞的.就是说一个线程调用read或者write()时,这个线程就已经被阻塞了,直到读取到一些数据为止,或者是完全写入.在此期间不能干其他的
事情. nio的非阻塞模式,当发送一个读取数据的请求的时候,如果没有读取到可用的数据,就什么也不会获取,且不会让线程阻塞.非阻塞写也是这样.非阻塞的IO的空闲时间可用用来做其他的操作所以,一个单独的非阻塞线程可以管理多个输入和输出通道(chanel)
另外NIO还有一个selector(选择器),它是可以管理多个输入输出的通道.大概就是这样
67、数据库视图?
原来我们公司做某某某项目的时候呢,用的是5张表的联查,然后用sql语句来写的话,比较慢,比较麻烦,然后我们把这5张表的联查创建了了视图,然后就直接查找的是视图,查询速度快,这个视图就是只能做查询,而不能做增删改操作。还有就是 Oracle 里面视图用的是CREATE VIEW 后面跟视图的名字,然后跟上sql语句
其实视图就是当成一张表进行操作了。
68、项目中你主要负责那块?
这就集思广益了,按照自己简历上的项目,然后针对性的找出自己要说哪几点,首先介绍这个是干什么的,然后这个是怎么用的,然后在哪里用的。
关于推送消息是怎么做到的?现在的推送消息插件:
首先呢,不推荐在web框架下在消息,效率低,可以使用一个开源的消息服务器,jmq,mqtt,xmpp协议都可以。
http长连接基本采用websocket实现,http协议的本身就比较复杂,websocket实现开销很高,而专用的消息协议简单了很多。如果每个人的消息都不同,建议采用xmpp。常用的插件有极光推送,信鸽推送,Kindle推送
以下了解:
XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
70、Js中的基本数据类型?
Undefined:只有一个值,就是undefined
Null;只有一个值,就是null,逻辑角度看,null值表示一个空对象指针
Boolean:类型只有两个值:true 和 false
Number:使用IEEE754格式来表示整数和浮点数值
String:由单引号或双引号括起来的字符序列,任何字符串的长度都可以通过访问length属性获得
71、专业书籍你都看过那些?
<<java 编程思想>> :作者是埃克尔,译者是陈昊鹏
这本书讲的是java基础语法到最高级的特性(有深入的面向对象概念,多线程,自动项目构建、单元测试和调试,等等等等,)这本书一共共22章,包括(多态、接口、通过异常处理错误、字符串、泛型、数组、容器深入研究、JavaI/O系统、并发以及图形化用户界面等一些内容)。这些丰富的内容都适合我们去学习,适合各个层次的Java程序员阅读;
《大型网站系统与Java中间件实践》作者曾宪杰: 它是淘宝的技术总监
这本书主要突出的重点是中间件三个字,中间件是分布式系统中一个非常重要的东西,它最重要的作用应该就是降低模块与模块之间的那种强依赖,然后不同的模块之间的依赖度降低了,就可以各自独立地开发自己的功能,这也可以说是软件工程发展的目标和驱动力。
这本书适合对分布式系统比较熟悉并且想要往中间件方面有一定研究的读者。
72、用过集群吗
solrCloud 是solr提供的分布式搜索方案 solrClund 是基于solr和zookeeper的分布式搜索方案, 主要思想是使用zookeeper作为集群的配置中心 特色功能: 1.集中式的配置信息 2.自动容错 3.近实时搜索 4.查询时自动负载均衡 。SolrCloud结构 需要由多台服务器共同完成索引和搜索任务 实现的思路是将索引数据进行shard(分片) 拆分,每个分片由多台的服务器共 同完成。当一个索引或搜索请求过来时会分别从不同的shard的服务器中操作 索引。 solrCloud需要 solr基于zookeeper部署,zookeeper是一个集群管理软件, 由solrCloud需要由多台服务器组成。由zookeeper来进行协调管理
73、项目中共部署了几个项目
我们的项目采用分布式的架构,每一个模块都可以作为一个项目,每一个项目都可以分为服务端和消费端,按照其功能分可以分为7个,分别是e3-web-manager,cart,item,portal,
Search,sso,order.这几个项目组成
74、有哪些需求文档?
根据项目的需求来做 一般是用在线的需求文档 就是用的石墨文档 是支持云端实时协作的企业办公软件 我们一般是这上头写需求 改需求的。
75、平常有自己搭服务器嘛?
有 dubbo solr Redis 都是我们自己搭建的 这些都是最基本的
76、你们公司有没有专门的测试环境,专门有一个地址 发布项目进行内部测试的?
有 我们有专门测试的服务 专门测试的服务 有一个测试的版本 有一个环境 比如说连接数据库 测试环境无非就是把配置变一下,一般都是有生成环境 开发环境 还有测试环境 一般都是这么分的 咱们公司是这样的吗 测试是怎么做的呢?
77、HTTP和HTTPS的区别
我们公司用的是HTTPS协议 他俩一个是加密 一个不加密 HTTPS是基于http开发的 是http的安全版 HTTPS协议需要到ca申请证书 一般免费证书很少 需要交费 他们两个链接的端口引入不一样 http是80 https是443
http是超文本传输协议 信息是明文传输的 HTTPS则是具有安全性的ssl加密传输协议
78、TCP协议,UDP协议,RPC协议,JMS协议?
都是通信协议
Tcp:tcp跟udp都是传输协议 主要区别是tcp协议连接需要3次握手 断开需要四次握手 是通过流来传输的就是确定连接后一直发送信息 传完后断开
Udp:udp不需要进行连接 直接把信息封装成多个报文直接发送 所以速度更快
Rpc:一种通过网络从远程计算机程序上请求服务 不需要了解底层网络技术的协议
Jms:(java mSSessaging service)是java的消息服务 jms的客户端之间通过jms服务进行异步的消息传输
79、库存警告是怎么使用的?
答:一般我们都是去,恩,就是说当我们每次做完出库后,都会有一个计算,比如说当我们的库存量小于100,或者是小于50,然后说就是会有相应的短信提醒,告诉库管这个商品少了,或者就是专门有一个预存信息的功能,就是定时的点击那个就可以知道哪些库存少了,就应该及时的去补充这个库存,其实就是查询库存数量小于多少的库存数就行
80、权限管理你们是单独的一个呀,还是怎么弄的?
我们之前做过权限管理,我们做的时候使用的五张表去做的这样的权限管理,有一张用户表,一张角色表,一张权限表,还有一张用户角色的桥表和角色权限的桥表。
我们是通过用户的id查询它所对应的角色,通过角色查询他所对应的权限,通过权限找到相对应的url.不知道咱们公司关于权限管理这块是怎么做的?
81、解释一下单链索引和联合索引?索引什么时候失效?
单链索引是指在表的某一列上创建索引,联合索引是在多个列上联合创建索引。单一索引可以出现在where条件的任何位置,而联合索引需要按照一定的顺序来写。在多条件查询的时候,联合索引的效率更高。我大概就了解这么多了。
索引并不是时时都会生效的,比如以下几种情况,将导致索引失效:
如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)
注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
对于多列索引,不是使用的第一部分,则不会使用索引
like查询是以%开头,会导致索引失效
如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
如果mysql估计使用全表扫描要比使用索引快,则不使用索引
此外,查看索引的使用情况
show status like ‘Handler_read%’;
大家可以注意:
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数
handler_read_rnd_next:这个值越高,说明查询低效
82、静态变量与非静态变量的区别如下:
1.内存分配
静态变量在应用程序初始化时,就存在于内存当中,直到它所在的类的程序运行结束时才消亡;
而非静态变量需要被实例化后才会分配内存。
2.生存周期
静态变量生存周期为应用程序的存在周期;
非静态变量的存在周期取决于实例化的类的存在周期。
3.调用方式
静态变量只能通过“类.静态变量名”调用,类的实例不能调用;
非静态变量当该变量所在的类被实例化后,可通过实例化的类名直接访问。
4.共享方式
静态变量是全局变量,被所有类的实例对象共享,即一个实例的改变了静态变量的值,其他同类的实例读到的就是变化后的值;
非静态变量是局部变量,不共享的。
5.访问方式
静态成员不能访问非静态成员;
非静态成员可以访问静态成员。
静态变量在类装载的时候分配内存,以后创建的对象都使用的该内存,相应的操作也就是对这块内存进行操作。也可以看作是另类的全局变量。
在WebSerivice中想只进行一次初始化,而不用每次都进行初始化这样占用大量资源。还可以对调用的服务进行管理,比如想把每次调用的服务进行排队执行,可以将想应信息放到Arraylist中,静态时钟中排队执行。
83、单点登录session共享是如何做的?
单点登录:
因为我们的项目是分布式的,我们单点登录使用cas做的,用户在cas系统中一次登录后,在其他项目中也能访问到该用户的信息
如果不用cas 的话怎么实现单点登录?
我们可以结合的redis一块使用,用户登录-->成功则存入redis,设置有效期,保存。进入主页面。并向cookie发送一个token值,当中包含用户信息。用户如果需要执行其他操作,需要携带token值去redis中进行校验,验证成功则继续下一步操作,不成功则重新进行登录操作。
84、MQ用过哪些?了解哪些?
我们常用的有 ActiveMQ、Redis
了解:RabbitMQ、ZeroMQ、Jafka/Kafka
ActiveMQ:它是apache下的一个子项目,类似于ZeroMQ ,是以点对点的技术实现队列,又有点类似于RabbitMQ,可以高效实现高级应用场景
有两种消息传递类型:
点对点,一个生产者只负责一个消费者,就相当于银行的一对一会员制度服务
发布/订阅模式: 也就是说一个生产者 多个消费者,相当于银行业务的普通制度
作用: 为了解决高并发
好处:支持多种语言和协议的,支持多种传送协议,提供高速消息持久化
怎么配置以及安装调用
安装:基于jdk,把ActiveMQ 的压缩包上传到Linux系统上,进行解压,使用bin目录下的 . /activemq start 命令启动
配置:springMVC.xml文件中引入activeMQ的xml文件
activeMQ.xml 文件中配置JMS 工具类,进行消息的接收发送等,再配置队列目的地已经订阅方式
Redis: 以key-value形式存在的非关系型数据库,本身支持MQ功能,我们可以把它当做一个轻量级队列服务;
安装:复制redis压缩包到Linux系统是哪个,进行解压,调用bin目录下 ./redis-server redis.conf ./redis-cli 进行启动。
配置:commons工程下配置xml文档 连接redis单机/集群版,导入工具包
RabbitMQ:开源的消息队列,支持很多协议,所以会非常重量级,适用于企业级的开发,对路由,负载均衡或者数据持久化有很好的支持。
ZeroMQ:具有独特的非中间件模式,最快的消息队列系统,主要是针对大吞吐量的需求场景,能实现复杂队列。
缺点:非持久化,电脑宕机数据会丢失。需要开发人员自己组合技术框架
Jafka/Kafka: apache下子项目,轻量级的高性能跨语言分布式消息队列系统
特性:快速持久化;高吞吐;完全分布式;支持Hadoop数据并行加载
85、开发环境是否统一
我们在开发项目时主要用到IDEA 、JDK1.7、 Maven、 Solr、 nginx、 Tomcat7.0、 MySql、 redis等开发工具或环境搭建,那么我们在开发同一项目的时候 开发环境必须统一,
公司项目的开发主要还是基于maven管理的聚合工程,分布式架构项目,我们每个人负责的功能模块都不相同,如果开发环境不统一,可能导致我们项目合并时候出现版本冲突,或者jar包等不兼容之类的事
86、数据库表纵表转横表
a) 表结构
1、横表: 主键、字段1、字段2……
如:姓名 语文 英语……
优点:一行表示了一个实体记录,清晰可见,一目了然。
缺点:如果现在要给这个表加一个字段,那么就必须重建表结构。
2、纵表:主键、字段1/2/3、字段值。
如:姓名 课程 成绩
优点:如果现在要给这个表加一个字段,只需要添加一些记录。
缺点:数据描述不是很清晰,而且会造成数据库数据很多。另如果需要分组统计,要先group by,较繁琐。
b )方法一:
聚合函数(max或者sum)配合case语句
例子:select 姓名,sum(case 课程 where ’语文’ then 成绩 end)as 语文 from 表名 group by 姓名
方法二:
使用pivot
select * from 表名 pivot (max(成绩)for 课程 in(语文,数学,英语)) 临时表
c) oracle SQL 实现竖表转横表
方法一:
--用decode实现,
SELECT 姓名,
SUM(DECODE(课程, '语文', 成绩)) 语文FROM 表名GROUP BY 姓名
方法二:
--用case when 实现
SELECT 姓名,
SUM(CASE 课程 WHEN '语文' THEN 成绩 ELSE 0 END) 语文 FROM 表名GROUP BY 姓名
区别:如果条件是单一值时,用decode比较简便,如果判断条件比较复杂是用case when实现
87、接口和抽象类的区别?
使用interface来定义一个接口,接口定义和类的定义差不多,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成。
[修饰符] interface 接口名 [extends 父接口名列表]{
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为public。如果省略则使用默认的访问权限。
接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符。一般情况下,要求首字母大写。
extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用extends关键字时,父接口名为必选参数。
方法:接口中的方法只有定义而没有被实现。
88、多线程怎么解决高并发?
synchronized关键字主要解决多线程共享数据同步问题。
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别:
synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信 时能够获得数据共享。
Synchronized用于线程间的数据共享, 而ThreadLocal则用于线程间的数据隔离。当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
89、使用ActiveMQ的好处?
减轻服务器压力,降低项目之间的耦合度(解耦),是做异步的.
索引用过哪些?
索引可以理解为数据1 的查询目录,建索引的目的就是 提高对表的查询速度;没有索引时,查询时全表检索,有了索引就可以根据索引快速查找需要的数据;但是索引也不能乱建,因为索引需要维护,会导致增删改的效率降低。会使数据的维护变的复杂,影响开发的效率,索引也会占用数据库的物理空间;所以我们一般在项目的开发阶段、测试阶段、试运行阶段都很少去创建索引,因为有了索引,系统bug造成垃圾数据特别不好删除。只有在项目正式上线后才去增加索引,以提高项目运行速度。索引我们一般都创建在经常作为查询条件的字段、排序的字段和作为关联关系的字段上边。尽量避免在大文本字段、数据量比较小的字段(比如性别),增删改性能大于检索性能的字段上边;另外,有些情况,即使增加了索引,索引也不会生效,比如:索引字段使用了不等于(!=或者<>)符合,用了函数、进行了运算,使用了is null或is not null,
和不匹配的数据类型进行比较、like查询时两边都用了%等;还有一个要注意的地方是,如果在多个字段上建立联合索引,那么组合索引的第一个列被where子句引用时,索引才会起作用。因为想要使用索引增加查询效率,必然要牺牲增删改效率,为了解决这个问题,我们经常对数据库做主从复制,读写分离。同时创建两个数据库,一主一从,两个数据库数据完全一致,主的数据库用来进行写的操作,操作后数据库会自动把数据同步到从的数据库,从的数据库用来执行读的操作。这样我们建立索引时,就可以只在读的数据库创建就可以了。这样就索引即能增加查询效率,有不影响增删改效率。这样做了之后,我们还可以对他进一步优化,比如数据库引擎的优化,主数据库因为执行增删改操作,所以用事务型引擎Innodb,
读的数据库,不需要事务,就可以用效率更高的MyIASM引擎。同时根据实际情况,也可以配置一主多从或者多主多从。索引的创建常用的有2中方式:CREATE 【UNIQUE】INDEX index_name ON table_name (column_list);或者ALTER TABLE table_name ADD INDEX index_name (id,name);修改用:ALTER TABLE table_name REBUILD INDEX index_name (column_list);删除用:DROP INDEX index_name ON talbe_name
或者:ALTER TABLE table_name DROP INDEX index_name
查看用:select * from all_indexes where table_name='student';
Conlum_list中多个字段用”,”号分割。
91、Mysql优化方案?
1. 使用支持mysql主从复制的版本
2. 在使用MySQL时使用索引
3. 优化sql语句
4. 优化MySQL服务,修改MY.INI文件,根据服务器配置缓存的大小
5. 根据服务器配置索引的缓存
6. 使用视图,将冗余字段放在一张表里
7. 使用第三方技术mycat,对数据库拆分,水平拆分和垂直拆分,我们用的水平拆分
8. 设置表内存放数据上限,同时通过mycat配置读写分离
92、Jvm内存结构
1.方法区(原数据区,永久区) 应用程序所有的类, 常量(不会变化的量)
2.栈:调用方法的 里面有 方法的形参和局部变量 方法的返回值
3.堆:new出来的对象
里面分为 新生代和老年代
新生代:eden from to 三个区 from 和to 是存活区 刚new出来的对象都放在eden区
from和 to 用来转储的内存
老年代:被垃圾回收很多次都没有回收(有没有被引用)
4.本地方法栈:虚拟机使用Native方法服务
5.Pc寄存器:当前执行的方法的地址,内存中速度最高的位置
93、Jvm优化?
1> 代码上尽量避免不必要的全局变量的使用,避免多层循环迭代,去除不必要的jar包,避免封装太多不必要的类的封装
2> JDK中自带的JMap查看内存信息,下载GC日志信息,,查看宕机信息,在Linux上设置tomcat上面catalina.bat文件设置Xms初始化堆的大小(128m)和XMx最大允许分配对内存(按需,一般根据我们项目的需要和内存的80%大小,如果不是强需修改,一般设置这两个参数大小相等)。在eclips上preferences-tomcat-jvm Settings中添加JVM参数,或者windows采用service.bat 中install Tomcat命令 里面有JVM的参数设置。
94、什么是读写分离?
这个我们项目中使用MyCat来做的,在mycat里配置好主库和从库,做增删改的时候是对主库进行操作,查询的时候是对从库进行操作,其实mysql本身从5.6以后的版本就带主从复制的功能了,他们是利用mysql里的log文件进行的数据同步.
95、线程和多线程话术?
线程就是一段可执行的代码块。
因为线程要服务于进程,一个进程有多个线程。
main方法就是主线程。多个线程一起执行就是多线程。
我们处理每一个请求就是一个线程,处理完请求就要被销毁。如果说有好多个请求,那么就要不停的创建并销毁。比较浪费资源。
那我们就用到了线程池,把准备就绪的线程放到线程池里面。需要处理请求的时候就调用线程。用完后再放回去,这样就可以防止高并发节省资源。
96、解决hashmap线程不安全问题?
可以通过collections集合工具类对不安全的线程进行包装,使其变成线程安全的,也可以在使用其时加synchronized关键字进行同步
97、如何实现爬虫的?
爬虫工具我们一般这样用 用的 HTTrack JSpider 结合使用的, HTTrack它是模拟一个浏览器比如说我要爬取京东数据 我就把京东的URl网址写上然后我们就去访问他HTTrack get请求回来 他就把Html'页码中所有代码都回来了然后分析Html代码 分析好用JSpider 它就是模拟的jquery 让jquery里面的选择器然后获取文本框,标签里面的内容 想获取商品名称,价格 还有图片等,都能趴下来,还有就是我从网上搜下来一个 它采用的线程池的方式 当时我们用这个,爬的京东数据,不知道多长时间 爬取了10~20G多。用写的带线程池的方式 咱们公司是用这样的工具呢 还是用市面上那些开源工具呢? 看是自己写呢 还能是成形的八爪鱼呢 这写我也都做过了了解。
括号附带:话术中没有
(在网络爬虫的系统框架中,主过程由控制器,解析器,资源库三部分组成。
控制器的主要工作是负责给多线程中的各个爬虫线程分配工作任务。
解析器的主要工作是下载网页,进行页面的处理,主要是将一些JS脚本标签、CSS代码内容、空格字符、HTML标签等内容处理掉,爬虫的基本工作是由解析器完成。
资源库是用来存放下载到的网页资源,一般都采用大型的数据库存储,如Oracle数据库,并对其建立索引。
常见的反爬策略主要有:
IP限制
UA限制
Cookie限制
资源随机化存储
动态加载技术
……
对应的反爬处理手段主要有:
IP代理池技术
用户代理池技术
Cookie保存与处理
自动触发技术
抓包分析技术+自动触发技术)
98、你有没有做过数据库建模,自己设计表和模块
一个有三年工作经验的人,一定要说设计过,(实际工作经验的程序员:在系统设计、需求文档,数据建模都应该有所涉及)数据库建模就是使用PowerDsiger工具,先分析项目需求,前端先出相应的原型,根据原型,我开始做相应的表,设计初期的时候表会有些小浮动修改等,再根据需求设计详细字段。如果后期客户需求改变时,表结构后期跟着调整,就是这样使用工具不断完善过程就是建模。
99、锁?
Java中的锁就是线程同步的锁 ,一般是在方法上面加一个synchroized关键字,锁的对象就是监视器 ,将当前对象作为锁定的对象,如果在代码块上进行加的话,自己可以指定自己要锁定的对象,比如说自己可以指定一个字符串,可以当做一个锁,指定一个类的class可以当做一个锁,只要这个锁的对象是不变的就行了。比如说指定一个类的class来当做一个锁,那么一个类的class本身就是不变的,当你在创建对象的时候就需要加载一个类,加载完成类肯定是不变的了。一般可以锁三种内型:当前对象,放在当前对象的方法上,第二种就是给一个字符串,第三种就是类.class。放在类上可以锁住一个对象,但是放在对象上肯定不能锁住一个类。
102、项目描述流程?
首先要介绍项目的背景,项目的技术所用的技术架构,项目中使用的第三方插件要给人介绍。项目后期的维护 测试 发布 运维是怎么做的,这些都要与人说清楚。
比如说这个爱普停车系统,他的背景就是现在的北京不仅堵车,而且找一个停车的地方也不好停,所以我们公司就有这个愿景,让用户用了我们这个爱普的软件后不管走在北京的哪一个角落,都能找到停车位。
这个是怎么做的,我们这个项目中就做到了定位,比如说我们去北京中心医院,我首先通过手机搜索附近的停车位,随后通过道航进行停车。我们的支付是我负责的模块,具体是通过车到大停车场之后,几分钟之后车辆不动,我就在后台数据库里给他定义一个时间,定义好之后。当用户点结束进程,用户通过支付宝或微信支付,这就是我们项目的背景。我们公司当初做的时候也就七八个人,因为这个项目的功能点也不是特别的多。三四个写后台,两个写前台,还有些ui的,还有项目经理,这样七八个人。使用的技术,也就是我们市面上的技术,springMvc spring mybatis。这个项目还用到第三方插件redis solr dubbo。这个项目我们做了六七个月,比如说我们第一个版本上线后出现的去多bug。比如定位不准,多人下订单时出现问题。比如说我们多人下订单的时候出现的高并发,我们当初是用acticveMQ消息队列解决了高并发的问题。当初
我们前端是用appcan写的。这样写的好处是,能在ios和安卓运行。
103、需求文档设计,接口文档设计,系统设计文档?
接口文档也叫接口api,三要素:url,参数,返回值。
需求文档写过吗?当然写过啊。客户在做需求调研的时候 ,我们也写过的。需求文档大概是这样写的。比如客户的那些需求呢理出来,理出来以后呢。
就根据一个功能点来说吧,就拿商品添加这个功能点来说吧,首先有个流程图要画出来,就用那个瑞搜,
有开始结束标签,中间有判断,首先开始,点击进入到登陆到我们的系统,然后点击新增商品的这个链接,然后有那么一个操作符,下一步点击这个商品
分类,这是一个操作符,接下来把这个商品分类显示出来,等等一系列的这个操作,我们要在需求文档里面写出来。流程图画完了,我们再说这个过程,
过程呢是分一二三四五六七八这样的步骤写下来的,写完这些步骤以后呢,还有产品得截图,什么样得截图呢?就是输出画面一,输出画面二这样得截图。
系统设计的写法是:首先要归纳商品中有哪些功能点,也有系统设计的流程图,这个流程图呢就不是需求文档那个页面逻辑的流程图了。是代码的流程图。里面
有规定到我们具体使用的哪个方法,类都要写清楚了。里面包括了有哪些字段。比如商品中设计到十几个字段,那么这十几个字段都得写。以及涉及到的数据库
表,数据字段都要写清楚了。
但这是我们原来传统的项目这样写。现在要做的是敏捷是开发,客户那边直接派人来我们公司驻扎,一些需求啥的我们和客户现场去定,定好之后就马上开发,叠加几个功能点测试,
测试没问题的话就很快发布了。
现在就是系统设计需求文档用的不多了,现在我们用这个现代化的管理工具了,比如springmvc里面有一些丝袜个第三方api文档,他可以生成记录文档的信息,就是前台能够显示出来的页面的
展示,类似接口文档的url,参数,返回值类型,这个参数干什么的那个干什么的,原来没用过这个丝袜个,后来听我们同事说用这个,后期我觉得我们公司也会用这个东西,因为写文档确实很耗时间的。
104、什么是RestFull风格架构?
就是一中架构风格,可以直接通过URL访问controller,我们前后端分离的项目不都是采用这样的方式架构的么.
105、ActiveMQ消息发送失败解决方案?
第一种用数据库配合着解决:
怎么配合呢咱们这边不是发送的商品的ID么,在发送之前把ID记录在数据库里面去,然后设置一个状态字段,0代表这个消息已经
发送成功。然后存在数据库里面,然后我们的状态就是0,然后就让往消息的队列里面去发去,就是时候我说第一种情况突然断电了
然后我的消息首先是记录在数据库里面了,然后他的那个状态是不是为0啊,然后抽个时间用定时器让晚上的两点到三点,让状态为0
的从新发送一下消息,这样是不是就可以解决断电的问题了,第二种我们如何去接受到一个消息,确定这个消息是消费了,这样也是
用我们的数据库来解决,如果这个消息消费了我们把这个消息状态设置为1,然后根据ID去数据库里面,把他的状态设置为1,如果为0就是
他上个消息没发送的问题了,这个我的消费。如果消费失败的话,就不会改变他的状态,还是0呗。这就是消息队列如何解决消息
同步的问题,还有突然断电的问题。
第二种解决:
在发送消息的时候设置提交的方式,改成手动提交的方式,在后台改成commit状态改成手动方式,如果发送成功的话,
然后commit手动提交方式。
106、解释下dubbo,云服务,和zookeeper?
问:Zookeeper关掉以后还能使用?还能调用服务?调用服务的时候是不是不经过zookeeper?
答:zookeeper关掉以后还能使用,你先是一个服务,然后注册到zookeeper,服务消费者第一调用的时候要拿到服务提供者的地址跟端口号。通过地址端口号用rpc可以调用。
不使用zookeeper服务可以调用dubbo框架么?
可以,Dubbo将注册中心进行抽象,它可以外接不同的存储媒介给注册中心提供服务,有zookeeper,
问:在一个项目里引用多个服务,怎么保证你引用的那个服务就是那个服务?
答:你打开不是有监控中心,你可以看服务后台它注册了多少个服务,消费端有多少个,提供者有多少个。端口号不同,一个服务启动起来会占用一个端口,而且是一个java jvm的进程。如果一台服务分配到两三台机器,会给负载均衡策略的。
问:负载均衡是怎么实现的?
答:所谓负载均衡就是对多台服务器进行流量分发一种服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。
问:用过线程池么?
答:现在都是了解,真实项目里面我们现在使用的是中间件,基本不使用线程去完成。
问:线程池怎么配的?
答:线程池在java里面有一个Executors,通过 Executors 可以方便的生成不同类型的线程池。但是要更好的理解使用线程池,就需要了解线程池的配置参数意义以及线程池的具体工作机制。
107、给我介绍一下Nginx
(What Nginx是什么)
对于nginx,它实际上是一个性能很高的http和反向代理服务器,它特点是内存占用少,并发访问能力强,据说BAT(百度 阿里 腾讯)这些大公司都使用这个技术,所以这个技术在咱们IT这个行业算是比较重要。
对于nginx,其实内容比较多,我还专门从淘宝上看了,有专门的书籍来介绍nginx,(或者说我还专门买了一本书,研究了一下),这里呢,我就介绍个大概吧。
在nginx源码层面上呢,它使用的是linux内核提供的一个新的叫做epoll的功能。可以实现单线程支持高并发的连接和请求.nginx底层实现,也是c语言的实现,指针这块用的非常灵活.它的机制是采用了事件驱动机制.之前我们要是解决高并发的话,肯定会第一用多线程,但是这个nginx它的一个主要优势采用的是单线程异步驱动这种形式来解决高并发,当然,再里边我确实还没有看到.
(Why 为什么用到nginx)
咱们还是说一下nginx两大主要的功能吧,一个是反向代理,一个是负载均衡,先说一下这个反向代理,那说反向代理,咱们还得先说一下正向代理,其实咱们平时调试开发都是正向代理,只不过我们不说这个词.比如吧,我们访问一台tomcat,默认端口号是8080,那我们访问的时候可能就是localhost:8080,这样顺着来呢,就可以理解成一个正向代理,就这样理解哈,其实正向代理这个概念呢我查过,严格来说呢是位于客户端和原始服务器之间的服务器。
这个时候,如果我们想要再来一台服务器呢,我们可以配一下,把端口号改成8081,通过访问不同的端口号来访问, 但是当我们项目要上线的时候,如果需要把一个项目如果部署到两台服务器上,比如淘宝,这么大,它的主界面不可能是在一台服务器上放着,就不能是访问8080或者8081这些端口了,这个时候,需要有一个代理的服务器,能够给这两台服务器做一个代理,直接不需要进行标明,就可以访问到任意一台服务器,找到这个主界面。这里呢,这个代理就可以代理这些服务器了,这个时候这个代理,我们可以理解成反向代理。反向代理严格的概念是通过代理服务器来接收网路上的请求,然后将请求转发给内部网路的服务器。而nginx可以干这个活,做这个代理,我们可以在nginx中配置端口,ip或者域名指向这些不同端口,甚至不同ip的服务器。这就是反向代理这个概念。
Nginx还有一个重要的功能叫做负载均衡,我们做服务器的集群,怎样保证集群中服务器被均等的进行访问呢,不能说我们认为搭建好了服务器的集群它就会均衡的去访问,这个时候我们可以统一的去访问nginx这个服务器,在nginx的配置信息中,去配置好这些服务器,它配置文件是这样的,只要你配上,默认访问的比率就是一样的,这个就是负载均衡,当然nginx更厉害的是可以配置权重,比如说哈,我两台服务器,其中一台性能比另外一个性能好2倍,那我是不是应该访问性能好的服务器频率更高一些,咱们就可以在nginx的配置文件中配置一个weight属性,指定权重。当然还有其他一些配置的,比如有些服务器需要整修,那咱们就可以配置某台服务器暂时down掉,这样用户访问的时候,就不会访问到这台服务器,当修好之后,我们在把这个配置信息干掉就行了。
(How 怎么配置Nginx)
其实,在公司里开发,我经历的这几家都配置了nginx的服务器,按照规范的做法的话,我们公司里边应该是有两台nginx服务器,一主一备,在这两台服务器上呢,都安装一个keep的软件,弄一个脚本,通过keepalive来检测服务器是否运行,主机挂了就把服务切到备用的这台上,这样的话基本就不会出问题了。当然,有的小公司就直接搞一台。挂了就挂了,不过nginx服务器很少挂,因为它高负载下cpu消耗依然很低
对于nginx配置的话,上家公司倒是配置过一次,我简单说一下吧。
首先是在服务器上安装nginx,这个按照文档来就行,网上有好多安装资料,自己也整理了好多安装文档,解压,make编译,make install安装,然后./nginx start启动,nginx安装算是比较简单。
然后配置nginx,nginx的配置其实就是配一个核心文件,在nginx中的conf下有一个nginx.xml,主要是修改这个配置文件,比如咱们配置反向代理和负载均衡服务器,配置一个proxy_pass 指向代理服务器,配一下upstream server指向要访问的ip和端口,这个可以配置多个ip,可以设置weight权重。
108、Nginx使用方法?
nginx就是一个反向代理服务器么,当时我们做的时候就是做的一个集群,就是前台一个页面配置了6个服务器,用n做的反向代理,当时我们还配了权重,就是使用n的权重,就是根据服务器的配置的高低给它设置权重的大小,后期我们设置了一个session共享的一个问题,因为我们项目不是分布式的嘛,我们用的是redis缓存保存的那个用户信息,然后把配置保存到本地去,然后去本地去配置,再去redis去数据信息,n大概就是这些东西
如果说的更深入一点的话就是听运维那边说的,n也有可能挂掉,当时我们搭建了两个n,takelaireber发送的一个贮备的n,它是发送的sintill协议,然后实时的去监控主服务器,互相监控,看这个服务器是否存活,一旦主服务器挂掉的话,它的备用服务器就会马上启动起来,我听运维的说的就是用的这个套路
当时我搭建的时候就是搭建了一个单机版,没有去搭建主备,你们要是搭配贮备n的话我跟我原来公司的运维要一下那个安装文档,然后过来给你搭一个这个主备的,你们公司用到内个nginx了吗
109、SpringBoot话术?
SpringBoot是我们最近的项目开始启用的。我个人觉得SpringBoot比以前的SpringMVC更好用,因为他的配置文件少了。原来SpringMVC的SSM整合的配置文件特别多,用了SpringBoot之后配置文件特别少了。我们用SpringBoot时结合的MyBatis去做得,SpringBoot基本上是一些YML文件,properties文件,MyBatis全程用的注解方式开发。SpringBoot和SpringMVC用法上大同小异,无非就是少了一些配置文件。启动SpringBoot服务器的时候是他自带的Tomca和Jetty服务器,可以通过main方法启动。配置上越来越简单。
110、什么是多线程?在哪里应用过?
线程就是可执行的代码段,线程要服务于进程,一个进程有好多个线程,main方法就是主线程,多个线程同时执行就是多线程,线程池就是把准备好的线程放到线程池里,如果处理请求需要调用线程的时候,就从线程池里去调用,用完以后再放回到线程池里,这样就防止高并发节省资源。
111、用过Junit的断言吗?
我们公司有要求做单元测试,但是都是后期补的,有的补全了,有的没补全,主要是我们公司里没有QA,所以这一块要求的不严, 其实断言就是断定结果的,就是符合我们预期输出的结果就返回true 不符合返回false 给出错误信息
@Before
初始化方法
@After
释放资源
@Test
测试方法,在这里可以测试期望异常和超时时间
@Ignore
忽略的测试方法
@BeforeClass
针对所有测试,只执行一次,且必须为static void
@AfterClass
针对所有测试,只执行一次,且必须为static void
@RunWith
指定测试类使用某个运行器
@Parameters
指定测试类的测试数据集合
@Rule
允许灵活添加或重新定义测试类中的每个测试方法的行为
@FixMethodOrder
指定测试方法的执行顺序
112、你们项目的边界是什么?
我们公司的项目边界都是架构师和项目经理定的,这个我没参与过.
项目边界其实就是针对整个项目要完成到什么程度的一个定义,就是至少需要哪些个功能点啦,达到什么样的要求,都可以称之为项目边界。
理论:在执行项目的过程中,有两次机会定义范围。高端范围在预定义的项目过程中加以定义。这些范围声明有助于建立项目的边界。收集商业需求时,范围定义得越详细越好。如果把范围看作是一个箱子,那么高端范围用来定义箱子的大小和形状;而需求则定义箱子的内容。
113、你们公司的double注册中心用的什么?
用的zookeeper,我们开发的时候用的是1台服务器,然后上线的时候用的是3台。
114、Redis做得时候用的是几台服务器?
我们开发的时候用的是windows版本的redis,然后是部署的时候是部署在linux系统上的,搭建了一个集群,是搭建了有6台服务器,6个节点。这6个节点是3主3备。Redis那边是有一个运行原理,是有一个那个乒乓协议,他们之间是可以发送心跳包,检测之间的节点是否存活。如果不存活的话,他内部是有一个投票选举机制,超过半数说这个节点死亡的话,就直接把这个节点排除出去了,然后让他的从节点工作,之后运维的人员把主节点修复好了,重新部署好了。然后redis会重新发送心跳协议包。差不多就是这个样子。
115、开发的时候Solr是怎么用的?
我们当时搭建的时候是搭建了一个Solr集群,我们搭建的这个集群的节点是靠的Zookeeper管理的,我们当时搭建的时候是搭建了三个zookeeper,四台Solr服务器来完成分片式的处理---solrcloud,当其中的一个Tomcat出现异常的时候,其他备用的Tomcat就会启动,继续工作,运维再去修复主节点的Tomcat,这样就不会出现互联网项目无法访问的情况,是我们开发的时候主备服务器的策略,
116、项目中有没有涉及到分库分表,怎么拆分的?(MyCat)
MyCat一个新颖的数据库中间件产品支持mysql集群,或者mariadb cluster,提供高可用性数据分片集群。MyCat分片根据其切分规则的类型,分为垂直切分和水平切分我们在项目中用的是水平切分。前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。
它支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,当我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分表,这时候应用要面对很多个数据库的时候,就需要对数据库层做一个抽象,来管理这些数据库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心作用。
所以也可以这样理解:数据库是对底层存储文件的抽象,而Mycat是对数据库的抽象。
117、说一下Docker
用过,Docker就是为了缩短代码从开发、测试到部署、上线运行的周期,能让项目具备可移植性,易于构建,并易于协作。(通俗一点说,Docker就像一个盒子,里面可以装很多物件,如果需要这些物件的可以直接将该大盒子拿走,而不需要从该盒子中一件件的取。比如说我们可以在这个容器里装好zookeeper,redis,mysql,tomcat等软件,用的时候直接用就可以,项目部署的时候,直接把当前的Docker给测试组就可以,或者是运维项目组就行.)
118、你们项目是分布式的,那你有了解过分布式事务么?
当然有了,因为我们项目比较大访问用户也比较多,我们把表都用mycat进行拆分了,我们当时拆分的方式是(说下第29题),我们在支付的时候,和下单的时候都用到了分布式事务.比如实时支付吧,一笔支付,是对买家账户进行扣款,同时对卖家账户进行加钱,这些操作必须在一个事务里执行,要么全部成功,要么全部失败。而对于买家账户属于买家中心,对应的是买家数据库,而卖家账户属于卖家中心,对应的是卖家数据库,对不同数据库的操作必然需要引入分布式事务。还有就是用户下单买家在电商平台下单,往往会涉及到两个动作,一个是扣库存,第二个是更新订单状态,库存和订单一般属于不同的数据库,需要使用分布式事务保证数据一致性。我们使用的解决方案是使用支付宝用得那个TCC补偿性分布式事务解决方案.
(what TCC是什么?)
TCC是三个英文单词的首字母缩写,分别对应Try、Confirm和Cancel三种操作,这三种操作的业务含义如下:
Try:预留业务资源
Confirm:确认执行业务操作
Cancel:取消执行业务操作
1、Try:尝试执行业务。
完成所有业务检查(一致性)
预留必须业务资源(准隔离性)
2、Confirm:确认执行业务。
真正执行业务
不做任何业务检查
只使用Try阶段预留的业务资源
3、Cancel:取消执行业务
释放Try阶段预留的业务资源
TCC的原理
我给你用这个账务拆分为说一下TCC吧,比如说我们账务拆分的业务场景是,分别位于三个不同分库的帐户A、B、C,A账户和B账户一起向C账户转帐共80元:
1、Try:尝试执行业务。
完成所有业务检查(一致性):检查A、B、C的帐户状态是否正常,帐户A的余额是否不少于30元,帐户B的余额是否不少于50元。
预留必须业务资源(准隔离性):帐户A的冻结金额增加30元,帐户B的冻结金额增加50元,这样就保证不会出现其他并发进程扣减了这两个帐户的余额而导致在后续的真正转帐操作过程中,帐户A和B的可用余额不够的情况。
2、Confirm:确认执行业务。
真正执行业务:如果Try阶段帐户A、B、C状态正常,且帐户A、B余额够用,则执行帐户A给账户C转账30元、帐户B给账户C转账50元的转帐操作。
不做任何业务检查:这时已经不需要做业务检查,Try阶段已经完成了业务检查。
只使用Try阶段预留的业务资源:只需要使用Try阶段帐户A和帐户B冻结的金额即可。
3、Cancel:取消执行业务
释放Try阶段预留的业务资源:如果Try阶段部分成功,比如帐户A的余额够用,且冻结相应金额成功,帐户B的余额不够而冻结失败,则需要对帐户A做Cancel操作,将帐户A被冻结的金额解冻掉。
(How TCC 怎么用的)
Github上有他们的源码,我们直接把源码挡下来,安装到我们本地的仓库里,用的时候我们把需要使用分布式事务的代码,上加上@Compensable注解,里面还有一些其他的属性配置上就可以了
119、关于日志处理
日志处理我们使用的是log4j,有一个log4j的配置文件,可以配置log输出的位置以及log的输出形式,并指定内容拼接方式。
对于整个项目,设置了一个全局异常,当出现异常信息的时候,将异常信息记录到log中
Logger logger = LoggerFactory.getLogger(GloableException.class);
logger.error("-------------出错了------------------");
当有些需要记录内容的信息,也可以通过日志文件进行记录。
对于用户登陆日志记录,我们需要自己封装一个日志记录的工具类,可以将用户登陆的信息记录到数据库中。(具体操作步骤看如下链接)
http://www.cnblogs.com/marcello/articles/4501479.html
120、关于悲观锁和乐观锁
悲观锁思路
解决线程安全的思路很多,可以从“悲观锁”的方向开始讨论。
悲观锁,也就是在修改数据的时候,采用锁定状态,排斥外部请求的修改。遇到加锁的状态,就必须等待。
虽然上述的方案的确解决了线程安全的问题,但是,别忘记,我们的场景是“高并发”。也就是说,会很多这样的修改请求,每个请求都需要等待“锁”,某些线程可能永远都没有机会抢到这个“锁”,这种请求就会死在那里。同时,这种请求会很多,瞬间增大系统的平均响应时间,结果是可用连接数被耗尽,系统陷入异常。
乐观锁思路
这个时候,我们就可以讨论一下“乐观锁”的思路了。乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功,其他的返回抢购失败。这样的话,我们就不需要考虑队列的问题,不过,它会增大CPU的计算开销。但是,综合来说,这是一个比较好的解决方案。
有很多软件和服务都“乐观锁”功能的支持,例如Redis中的watch就是其中之一。通过这个实现,我们保证了数据的安全。
121、JAVA中常用的加密算法
对于不可逆的加密算法有
MD5和SHA, 通过散列算法进行加密SHA加密比MD5安全性更高,常用SHA-256加密算法。
DES加密算法,对称加密,客户端和服务端公用一个key,该key最好是随机生成,对于这种加密算法加密效率高,但是据说24小时以内可以破解。
AES加密算法,不对称加密算法,通过公钥加密,私钥解密,私钥加密,公钥验证签名。(支付宝) 是目前比较安全的加密算法,但效率偏低。安全性是DES加密算法的1000多倍数。
122、MySQL和Oracle区别
MySQL:中小型数据库,开源免费,轻便简单
Orcale:大型数据库,价格高昂,性能好,支持大并发,大访问量
MySQL:主键自增
Orcale:不能主键自增
mysql:可以用双引号包字符串
Orcale:要用单引号
MySQL:分页关键字 limit实现
Orcale:用ROWNUM,实现复杂
123、ERP系统里主要是干什么?
ERP是一种企业资源管理与业务流程管理的计算机系统,对企业内部所有的经营活动,包括采购,财务,人力资源,物料等等的整合,最终达成高效化经营的目的。
124、什么是接口
前后端交互会用到接口,三要素:URL,参数,返回值类型,请求方式get,post
125、你们做的这个项目大概有多少接口?
大概有几百个,涉及到接口三要素的就是接口
126、什么是策略?
就是解决项目中的问题,solr,redis,等等。
127、你平常和哪几个部门进行沟通?协调哪些内容?
产品经理:沟通一些业务逻辑、功能点。
测试人员:把一些bug提交到BugFree的平台,有哪些bug然后改一下
128、开发过程中你是如何确保开发的进度和质量的?
一般都是项目经理定的,规定一下项目工作日,根据功能点来估计一下工作日
129、项目中遇到的难点你们是怎么克服的,有什么固定的标准流程吗?
比方说公司要用redis,买一些关于redis实战的书进行学习,网上也找找关于redis方面的资料进行学习,遇到一些问题问问我们项目组长,技术总监,他们有什么响应的解决方案,然后自己去解决去。
130、项目迭代是怎么实现?
项目迭代就是做一些相关的更新什么,更新完了之后会有一个系统集成测试(SIT测试),测试完了之后再进行上线。
131、内存溢出,内存泄漏
内存溢出指的是jvm内存溢出,通过调整堆,栈的大小来解决。
代码中出现死循环或递归调用也会造成内存溢出。
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
132、GC过程
再说算法之前,我们来先说一下JVM中的新生代和老年代,新生代就是用来存放刚被new出来的对象,一般情况下占堆的1/3空间。而新生代中又分为
3个区:Eden区java新对象的出生地,当内存不够的时候就会带有调用MinroGC,对新生代进行回收。
ServivorTo:保留MinroGC一次的幸存对象
ServivorFrom:上次的幸存者,被这次gc的对象
老年代:存放应用程序中生命周期长的内存对象
然后,我们的JVM回收算法有4种
第一种:标记-清除法
分为:标记,请除
标记阶段:直接在内存里标记无用的对象,然后清除阶段直接回收被标记的对象;
缺点:形成内存碎片,一些大的对象无法找到足够的空间而触发新的垃圾收集动作。
第二种:复制算法:
将内存划分为大小相等的两块,当一块的内存用完了,就讲还存活的对象复制到另外一块上面,然后将之前的那块清理掉
缺点:浪费内存太多(对老年代的使用,效率低)
第三种:标记-整理算法
将存活的对象都向一端移动,然后直接清理掉这端边界以外的内存
第四种:分代收集算法:(当前商业虚拟机都采用这个)
根据对象的存活中期的不同将内存划分为几块,一般Java堆分为新生代和老年代
新生代:用复制算法 老年代用标记整理算法进行回收
133、App接口开发
由于移动端app一般时不能直接访问数据库的,所以需要我们Java后台开发接口,供移动端去调用;
App接口的开发一般都是restful风格的接口。就是不需要跳转页面,都是直接返回需要的数据。所有的方法上都需要@ResponseBody注解,把返回结果转换成json。所以我们一般用@RestController代替@controller;
因为app接口如果获取不到想要数据,就很可能发生闪退,所以我们需要在controller中的所有方法中,用try catch捕获异常,把异常也返回。
为了让用户识别异常,我们一般需要定义一组错误编码。
由于接口比较多,为了方便客户端处理接口返回数据,我们定义了一个统一的返回对象类。里边主要包含三个参数:Boolean success,String code,Object data;
安全方面考虑,接口最后都要把http协议转换成https(http+CA证书)协议。
在接口的拦截器里边,采用对称加密的方式,进行签名认证。 对称加密就是服务端给调用端一个appid和一个appsecret;
接口文档:接口说明、接口的url,传入参数、响应参数。
接口自己测试:一般在浏览器上安装一个restclient的插件,用这个插件就可以测试。
接口的调试:方法一:手机连接公司的内外;方法二:通过Nginx把自己的ip代理到外网。
134、第三方支付
B2C电商的支付,一般由于支付金额比较小,支付比较频繁,所以一般采用第三方支付,常用的第三方支付有:支付宝、微信、聚合支付、付钱啦等。他们的原理都差不多。都是在点击支付时,直接调用第三方支付接口,传入appid、appsecret、订单编号、订单金额、回调url,直接跳转到第三方支付页面,接下来的支付过程,我们都不需要管,支付成功以后,第三方支付平台会直接回调我们的url。给我们返回:状态码、订单编号、支付流水号三个参数。我们首先根据订单编号,找到我们的订单,把支付流水号和状态码更新到我们的订单里边。回调url,一般有两种,一种用同步get方法回调,一种用异步的类似ajax方法回调,同步方法回调,一般是成功以后才会回调,并且只回调一次,回调成功以后我们可以直接跳转到我们的支付成功页面、异步方法回调,一般要求我们返回一个success字符串,第三方平台如果没有接受到success,就会认为没有调用成功,他会重复多次调用。比如支付宝会在25小时之内,调用8次;一般情况下第三方支付都采用第二种方式,因为比较安全,但支付宝是同时采用了两种。
我之前接触过一个B2B的电商,他们由于交易金额比较大,第三方支付无法实现,所以是直接和银行对接。大体上是,首先平台和银行签订合同,银行为平台开设一个总账号,当企业在平台注册以后,平台会为企业调用银行接口,创建一个子账号,这个子张号是挂在总账号下边的,也是一个在银行实际存在的账号,但是,只能通过外部银行卡给里边转账,而不能给外部银行卡转出。可以在子行号直接互相转账。
135、第三方登录
第三方登录,我的理解就是基于用户在第三方平台上已有的账号和密码来快速完成己方应用的登录或者注册的功能。遵循一个Oauth2.0国际通用协议,允许用户在不提供用户名和密码的情况下,让第三方应用访问一些资源。使用第三方登录时,我们不需要用户再次输入用户名和密码,而是直接通过一个唯一openid来进行授权登录。对于普通用户来说,如果能用QQ、微信、百度、新浪这些平台的账号一键注册登录各个平台,无疑会方便很多。对于我们的应用来说,通过授权,借助QQ、微信这些用户量比较大的第三方平台增强自己的知名度也非常划算。
我们的平台集成了QQ、微信、百度、新浪四种第三方登录方式,实现的方式都是类似的。首先去各大开放平台进行注册成为开发者,并创建应用,填写回调地址,获取appid(应用唯一的识别标志)、appkey(给应用分配的密钥),(名称可能不一样);下载api文档和sdk开发工具包;就可以开始开发了。
首先在我们网站的登录页面根据api集成第三方登录的logo图标,并给与点击事件,当用户点击此图标时,发送请求,直接跳转到第三方平台的登录页面,第三方平台也会自动检测电脑是否有已登录的账号。登录成功以后,第三方平台会自动调用我们传递的回调地址,并传递回一个code参数;我们拿到code以后,再次调用第三方api提供的接口,传入code、app_id、appkey等参数,调用获取access_token的接口(接口调用,有第三方提供的sdk包,直接导入jar包,根据api文档,传递参数调用方法就可以,我们没必要太过关心第三方平台是用webservic接口或httpclient接口。)。获取到access_token同时,会获取到openid,拿到openid以后,就相当于拿到了登录授权。用openid去自己的用户表中查找是否与对应的用户,如果有,就直接查出用户信息,创建自己的session就可以了。如果没有,则新创建一个用户,把openid放进去。如果还需要其他信息,可以通过openid再次调用第三方平台的接口获取用户信息,如果用户信息还是不够,可以创建完用户以后再次跳转一个页面,让用户不全信息。信息补全以后,创建session,完成登录。这样一个第三方登录就完成了。
136、关系型数据库和非关系数据库的区别?
关系型数据库是表与表之间有关系比如一对多, 多对一,等值连接什么的,非关系型数据库就是里面没有多张表,没有什么关联
137、docker容器常用的命令
# 镜像和容器的区别?
- 镜像可以理解为java类, 容器理解成为java中的对象.
# 命令总结
- 启动docker命令: systemctl start docker 停止 stop 状态 status
- 查看镜像文件命令: docker images
- 搜索镜像: docker search 搜索名字
- 拉取镜像: docker pull 镜像名字
- 删除镜像: docker rmi 镜像Id
- 删除所有镜像 docker rmi `docker images -q`
- 创建交互式容器: docker run -it --name=mycentos centos:7 /bin/bash
- 退出容器: exit
- 创建了守护式容器: docker run -di --name=mycentos2 centos:7
- 进入守护容器: docker exec -it mycentos2 /bin/bash
- 查询所有的容器: docker ps -a
- 查询正在运行的容器: docker ps
- 查询最后一次运行的容器 docker ps -l
- 查询已经停止的容器: docker ps -f status=exited
- 启动容器: docker run 容器id/容器名字
- 文件复制(宿主机与容器文件的复制): docker cp 本地目录 容器名称:目录 docker cp /usr/local mycentos2:/usr/local
- 目录挂载(创建容器的时候,把宿主机的一个文件目录,与容器中的某一个目录进行映射,达到的目的是我们往宿主机的目录中添加了文件,他会直接自动复制到对应的容器目录中,): docker run -di -v /usr/local/myhtml:/usr/local/mh --name=mycentos3 centos:7
- 查询容器中的ip地址(因为我们后期会创建多个容器,容器与容器之间要进行同行,就得依靠这个IP地址): docker inspect 容器名称
- 删除容器: docker rm 容器名称
- 删除全部容器: docker rm `docker ps -a -q`
# 备份和恢复流程
- 备份流程: 容器-->(docker commit yizhigou_nginx mynginx)-->镜像-->tar压缩包docker save -o mynginx.tar mynginx
-
- 恢复流程 压缩包--(docker load -i mynginx.tar)--> 镜像--(docker run -di --name=yizhigou_nginx -p 80:80 mynginx)-->容器
138、Spring中@Autowired和@Resource的区别?
@Autowired默认的是按照类型进行注入, 如果没有类型会按照名称(红色字体)进行注入.
如果想直接按照名称注入需要加入@Qualifier("gatheringDao")
@Autowired
@Qualifier("gatheringDao")
private GatheringDao gatheringDao;
@Resource默认的会按照名称注入,名称找不着会按照类型来找,如果这里写了名称,就直接按照名称找了不会按类型找@Resource(name = "aaa")
@Resource
private GatheringDao gatheringDao;
你在项目中有没有使用到mongodb?
用过,在数据量比较大的时候,还有写入操作比较频繁的时候,还有数据不是特别重要的情况,因为mongodb有可能会丢数据,比如说商品评论,里面的数据也不是特别重要,缺一条也无所谓,我们就用的mongodb
你的工程是如何操作MongoDB的?
我们使用spring data mongodb
在项目的哪些场景下使用MongoDB ?
吐槽 、文章评论 、商品评价.
为什么在吐槽和文章评论中使用Mongodb而不使用mysql?
吐槽和评论都是数据量较大且价值较低的数据,为了减轻mysql的压力,我们使用mongodb
SpringBoot和SpringMVC与springCloud关系?
1.springboot是springmvc的升级版,其实就把springmvc里的配置文件,改为全注解的开发
2.SpringCloud通过Springboot把其他的通信组件等等进行了封装,你如果使用SpringCloud的,那就必须得使用SpringBoot,使用SpringBoot的话不一定非得使用SpringCloud.
Solr与ElasticSearch的区别?
他俩的底层都是基于lucene实现的,都是使用的lucene的倒排索引实现的,solr在实时建立索引的时候会产生IO阻塞查询性能会比ElasticSearch差一些,还有就是因为Solr自身不支持分布式,ElasticSearch是实时处理数据,而且默认的支持分布式的,可以组成一个网络,如果其中一台服务器宕机,会分配其他节点工作,可以扩展多台服务器,所以查询效率会更快,据说可以处理PB以上级别的数据.
145、redis和mongoDB的区别?
mongodb是非关系型数据库最像关系型数据库的一种数据库,我们一般还是用它当存储去用,但是Redis是key和value方式存储的,我们可以把他用来优化项目,把一些频繁访问的数据存到redis中,不用频繁的访问数据库了,给mysql数据库减轻压力.
关于IK分词器扩展词汇实现自动添加用户搜索热词的方法.你有什么见解?
所谓热词就是用户经常搜索到的词语,我们给他放到自己的分词器里当成一个词进行搜索,比如说经常说的”大吉大利今晚吃鸡”,这样的词就可以当做是热词,我也没在项目里实际的做过,但是我知道在大数据里有一个wordcount技术可以实现这个热词分析,就能给你添加到自定义词典中.
146、logstash定时任务去执行同步索引库,每次去读取扫描表,千万级别的数据会不会突然死机啊?
Ogstash本来就很吃资源, 如果你做数据同步的服务器,配置必须得高, 内存怎么也得几十个G, 现在银行里的数据几乎都是TB级别的内存了,所以这个可以用硬件去解决这个问题.还有就是这个数据不一定非得是实时.
147、前后端通过接口调用的时候,接口安全如何做的?
我们使用JJWT做的前后端接口的安全控制,访问我们接口的时候必须通过我们约定好的在head中存放token信息,判断这个token信息是否是我们这个后台给提供的token信息,token信息在什么产生的?是在登录的时候产生的token码.还有一种情况,用户初次进入到我们的系统,用户是没有登录的,这时候我们跟前台确定一个token码,前台要给我我们TOken码+时间戳请求我们后台,我们后台会根据约定好了,进行相应的截取时间戳和token码,进行相应的判断.
147、SpringCloud的常用组件挨个介绍一下?
Eureka组件(服务发现)音标(ju`ri:kə): 相当于我们使用的dubbox的时候zookeeper注册中心.
Feign组件: 调用服务的时候用的组件
Hystrix(hist`riks)熔断器: 我们在调用服务的时候,有可能涉及到服务的连锁调用,比如说A服务调用B服务,B服务里还调用了C服务, 使用A服务的时候,B服务和C服务都得正常运行才可以使用,B调用C没有调通的时候, B直接给A返回内容, 不至于像以前报错.
服务网关 zull: 前后端进行调用的时候可以,可以走同一个IP地址,因为项目端口号太多,配置这个以后就可以直接走一个端口号,他自动会给你分配具体调用的哪一个端口
分布式配置Spring Cloud Config:我们把多个项目的配置文件归置为一个,修改配置文件以后,不用再重新部署某一个项目啦.
消息总线:Spring Cloud Bus: 修改完配置文件以后不用重启项目.
148、面试心得
面试终极秘籍:笑
笑。大家在面试过程中一定要学会笑。笑可以减少紧张情绪,笑可以缓解尴尬,微可以拉近和面试官的距离。大家记住一点,面试官都讨厌总是面试,他非常希望你能成功。所以不要因为回答不上问题而苦着脸,不要尴尬,尴尬时就傻笑。
给予面试官信心
面试过程中,要对自己有信心,还要让面试官对你有信心。所有的答案都要给面试官肯定的回答。坚决不能说,可能、或许、好像这样的词语。
技术不行业务补
技术的终点是业务,脱离业务的技术,只能是纸上谈兵。技术就是为了实现业务的。技术上总有解决不了的问题,这时候从业务考虑,完全可以用其他方法实现。我们java涉及到的技术点太多了,没有谁能把不同面试官的所有技术问题都打上来的,现在大家都面临面试了,没有那么多时间去学习了,如果你还纠结于技术的学习,那么你会发现,技术是永远学不完的,学的越多,不懂的越多,越学越没有自信。那么怎么办呢?
一句话:“技术不行,业务补”,针对你的第一个项目,多想想,仔细想想,打好草稿,你的项目是做什么的,主要业务流程是什么,你的模块的独特性在哪里,项目主要有哪些用户,项目的亮点在哪里,赢利点在哪里,同类竞争网站有哪些。项目的主要架构是什么样的,开发过程中遇到了哪些问题,有哪些问题是遗留没有解决的。等等。首先给自己定一个目标,打一份草稿,这份草稿,可以保证你,面试官一句话不说,你自己介绍项目就能介绍30分钟以上。可能面试的时候,很多面试官不给你说业务的机会,但是你一定要有所准备,当技术说不上来的时候,就说业务,用业务来描述技术。当然在描述业务的时候,也不能光说业务,在业务中引出技术,只有说出为什么在这块要使用这个技术,使用这个技术做什么,用它有什么好处就可以了。
传递正能量
面试中,成功的最佳办法,就是不断给面试官传递正能量,告诉面试官,
我能吃苦,我能加班,我能出差。
给我分配了任务,我就会积极去解决,不会逃避,不找理由,不找借口,方法总比问题多。只要用心,就没有解决不了的问题。
我有很强的学习能力,经常喜欢去网络上自己学习。
我有很多同行业的朋友,我们经常交流,互相帮助。
我认为技术没有难不难,只有会不会,我们这一行业新技术层出不穷,关键在于学习力,我对我的学习力还是非常自信的;
这个技术点,如果让我做,我肯定能做,就是不知道该如何表达。
每个知识点要讲透彻,把知识点串起来,不给面试官提问的机会
准备3个技术点,每次面试都要想办法讲出来,逐渐掌握主动权