面试:第三章:中级综合

SSM框架面试问题

讲下springmvc框架的工做流程

一、用户向服务器发送请求,请求被SpringMVC的前端控制器DispatcherServlet截获。html

二、DispatcherServlet对请求的URL(统一资源定位符)进行解析,获得URI(请求资源标识符),而后根据该URI,调用HandlerMapping得到该Handler配置的全部相关的对象,包括Handler对象以及Handler对象对应的拦截器,这些对象都会被封装到一个HandlerExecutionChain对象当中返回。前端

三、DispatcherServlet根据得到的Handler,选择一个合适的HandlerAdapter。HandlerAdapter的设计符合面向对象中的单一职责原则,代码结构清晰,便于维护,最为重要的是,代码的可复制性高。HandlerAdapter会被用于处理多种Handler,调用Handler实际处理请求的方法。java

四、提取请求中的模型数据,开始执行Handler(Controller)。在填充Handler的入参过程当中,根据配置,spring将帮助作一些额外的工做mysql

消息转换:将请求的消息,如json、xml等数据转换成一个对象,将对象转换为指定的响应信息。nginx

数据转换:对请求消息进行数据转换,如String转换成Integer、Double等。 程序员

数据格式化:对请求的消息进行数据格式化,如将字符串转换为格式化数字或格式化日期等。angularjs

数据验证:验证数据的有效性如长度、格式等,验证结果存储到BindingResult或Error中。web

五、Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象,ModelAndView对象中应该包含视图名或视图模型。面试

六、根据返回的ModelAndView对象,选择一个合适的ViewResolver(视图解析器)返回给DispatcherServlet。ajax

七、ViewResolver结合Model和View来渲染视图。

八、将视图渲染结果返回给客户端。

以上8个步骤,DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver等对象协同工做,完成SpringMVC请求—>响应的整个工做流程,这些对象完成的工做对于开发者来讲都是不可见的,开发者并不须要关心这些对象是如何工做的,开发者,只须要在Handler(Controller)当中完成对请求的业务处理。

 

图片怎么上传

前端实现异步上传,后端使用springmvc的MultipartFile类型来接收,放到分布式图片服务器中,服务器返回图片路径把路径返回页面回显图片,开发或者测试环境能够使用FastDFS

 

微服务和SOA有什么区别?

若是一句话来谈SOA和微服务的区别,即微服务再也不强调传统SOA架构里面比较重的ESB企业服务总线,同时SOA的思想进入到单个业务系统内部实现真正的组件化。说的更直白一点就是微服务被拆分的粒度更小

 

spring框架AOP执行原理简单说下?还有就是AOP在事务管理方面是怎么实现的?

Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的所有方法,而且在特定的切点作了加强处理,并回调原对象的方法。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理经过反射来接收被代理的类,而且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。若是目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,能够在运行时动态的生成某个类的子类,注意,CGLIB是经过继承的方式作的动态代理,所以若是某个类被标记为final,那么它是没法使用CGLIB作动态代理的。

AOP在事务管理方面,Spring使用AOP来完成声明式的事务管理有annotation和xml两种形式。开发中,方便代码编写,不少时候都是在spring配置文件中配置事务管理器并开启事务控制注解。在业务类或业务类方法中添加@Transactional实现事务控制。

 

Spring 分布式事务如何处理的?

第一种方案:可靠消息最终一致性,须要业务系统结合MQ消息中间件实现,在实现过程当中须要保证消息的成功发送及成功消费。即须要经过业务系统控制MQ的消息状态

第二种方案:TCC补偿性,分为三个阶段TRYING-CONFIRMING-CANCELING。每一个阶段作不一样的处理。

TRYING阶段主要是对业务系统进行检测及资源预留

CONFIRMING阶段是作业务提交,经过TRYING阶段执行成功后,再执行该阶段。默认若是TRYING阶段执行成功,CONFIRMING就必定能成功。

CANCELING阶段是回对业务作回滚,在TRYING阶段中,若是存在分支事务TRYING失败,则须要调用CANCELING将已预留的资源进行释放。

 

Springboot用过没,跟我说说,他的特色?

Springboot是从无数企业实战开发中总结出来的一个更加精炼的框架,使得开发更加简单,能使用寥寥数行代码,完成一系列任务。

1)  Springboot解决那些问题

a)    编码更简单

 i.          Spring框架因为超重量级的XML,annotation配置,使得系统变得很笨重,难以维护

ii.          Springboot采用约点大于配置的方法,直接引入依赖,便可实现代码的开发

b)    配置更简单

Xml文件使用javaConfig代替,XML中bean的建立,使用@bean代替后能够直接注入。

配置文件变少不少,就是application.yml

c)    部署更简单

d)    监控更简单

Spring-boot-start-actuator:

能够查看属性配置

线程工做状态

环境变量

JVM性能监控

支付接口是怎么作的?

微信支付

调用微信的支付接口,参考微信提供的api

使用了微信的统一下单接口和查询支付状态接口

每一个接口须要的参数放入到map中使用微信提供的sdk转成XML字符串,httpClient远程提交参数和接收结果。

支付宝支付

详情https://www.alipay.com/

SpringBoot相关面试题

什么是 Spring Boot?

Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各类启动器,开发者能快速上手。

为何要用 Spring Boot?

Spring Boot 优势很是多,如:

独立运行

简化配置

自动配置

无代码生成和XML配置

应用监控

上手容易

Spring Boot 的核心配置文件有哪几个?它们的区别是什么?

Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。

application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。

bootstrap 配置文件有如下几个应用场景。

  • 使用 Spring Cloud Config 配置中心时,这时须要在 bootstrap 配置文件中添加链接到配置中心的配置属性来加载外部配置中心的配置信息;
  • 一些固定的不能被覆盖的属性;
  • 一些加密/解密的场景

 

Spring Boot 的配置文件有哪几种格式?它们有什么区别?

.properties 和 .yml,它们的区别主要是书写格式不一样。

 

Spring Boot 的核心注解是哪一个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了如下 3 个注解:

@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。

@EnableAutoConfiguration:打开自动配置的功能,也能够关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。

@ComponentScan:Spring组件扫描。

 

开启 Spring Boot 特性有哪几种方式?

1)继承spring-boot-starter-parent项目

2)导入spring-boot-dependencies项目依赖

 

Spring Boot 须要独立的容器运行吗?

能够不须要,内置了 Tomcat/ Jetty 等容器.

 

运行 Spring Boot 有哪几种方式?

1)打包用命令或者放到容器中运行

2)用 Maven/ Gradle 插件运行

3)直接执行 main 方法运行

 

Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

 

你如何理解 Spring Boot 中的 Starters?

Starters能够理解为启动器,它包含了一系列能够集成到应用里面的依赖包,你能够一站式集成 Spring 及其余技术,而不须要处处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。

Starters包含了许多项目中须要用到的依赖,它们能快速持续的运行,都是一系列获得支持的管理传递性依赖.

 

如何在 Spring Boot 启动的时候运行一些特定的代码?

能够实现接口 ApplicationRunner 或者 CommandLineRunner,这两个接口实现方式同样,它们都只提供了一个 run 方法.

 

Spring Boot 有哪几种读取配置的方式?

Spring Boot 能够经过 @PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量

 

电商项目业务面试问题

哪些状况用到activeMq?

商品上架后更新ES索引库、更新静态页、发送短信

 

秒杀的时候,只有最后一件物品,该怎么去抢或者分配?

秒杀商品的库存都会放到redis中,在客户下单时就减库存,减完库存会判断库存是否为大于 0,若是小于0,表示库存不足,刚才减去的数量再恢复,整个过程使用redis的watch锁。

 

你项目对于订单是怎么处理的,假如一个客户在下订单的时候没有购买怎么办,对于顾客在购买商品的时候大家怎么处理大家的库存?

订单表中设置了一个过时时间,天天会有定时任务来扫描订单表数据,若是到达预订的过时时间没有付款就会取消此订单交易。

关于库存的设计是这样的:

普通商品在发货时才去更新库存,若是库存不足商家会立刻补货

秒杀的商品会在客户下单时就减库存,若是在规定时间(半个小时)没有付款,会取消此订单把库存还原

 

redis存储格式的选择

redis支持的数据结构总共有5种:hash、value、list、set、zset,其中项目中用到最可能是hash

 

商品中的数据是哪里来的

商品表的数据是在商家管理后台中由商家录入的。数据分别录入到商品表、商品描述表和商品项表

 

当初设计项目时预计的访问量计划是多少

访问量计划是3000至5000

 

简单介绍一下你的这个项目以及项目中涉及到的技术框架以及使用场景以及你主要负责项目中的哪一块?

项目介绍时,先总体介绍是什么项目,项目主要是作啥的,为何会作这个项目(市场需求)?例如:XXX电商项目,是一个B2B2C综合电商平台。由三个系统组成,包含:运营商管理后台、商家管理后台、网站前台。运营商平台主要负责基础数据维护、商家审核、商品审核等。商家管理后台主要负责商家入驻、商品录入/修改、商品上下架等。网站前台主要负责商品销售。包含:网站首页、商品搜索、商品详情展现、购物车、订单、支付、用户中心等模块。

再介绍本身在项目中作的功能模块。例如:运营商管理后台的品牌、规格数据录入,已经商品管理后台商品录入功能。同时,实现了网站前台系统中的商品搜索、购物车等功能模块。

而后介绍里面使用的技术:例如:dubbo分布式框架、ssm、es、redis、activeMQ、支付宝支付等等。最好是结合技术讲解项目功能点如何实现。

 

秒杀系统中如何防止超售?如何避免脚本进行恶意刷单?

防止超售解决方案:将存库从MySQL前移到Redis中,全部的写操做放到内存中,因为Redis中不存在锁故不会出现互相等待,而且因为Redis的写性能和读性能都远高于MySQL,这就解决了高并发下的性能问题。而后经过队列等异步手段,将变化的数据异步写入到DB中。当达到库存阀值的时候就不在消费队列,并关闭购买功能。

避免脚本恶意刷单:采用IP级别的限流,即针对某一个IP,限制单位时间内发起请求数量。

 

单点登陆大家是本身编写的仍是使用通用的CAS?

项目使用通用的CAS框架。

 

若是一个用户的token被其余用户劫持了,怎样解决这个安全问题。

a、在存储的时候把token进行对称加密存储,用时解开。

b、将请求URL、时间戳、token三者进行合并加盐签名,服务端校验有效性。

c、HTTPS对URL进行加密

 

项目部署上线后,运营商管理,商品审核等后台流量问题?

先询问流量是指哪方面?流量分为三种,一种是商家流量,另外一种是用户流量,第三种运营商流量。

解决方案:

      这三种流量对系统运行形成很大压力,随着项目上线时间增加,压力会愈来愈大,所以咱们要减轻系统访问压力 ,就须要作一系列优化措施。

       具体优化以下:

数据层面的优化:

从数据库层面作优化,好比:索引,缓存,集群,读写分离,主从复制,分表,分库。

从数据库设计层面的优化:好比减小表关联,加入冗余字段

从缓存方面优化:好比redis实现数据缓存,减轻数据库压力

从搜索上进行优化:好比查找索引库

 

项目层面的优化:

采用面向服务的分布式架构:分担服务器压力 ,提升项目并发量。 好比dubbox+zookeeper分布式架构

采用分布式文件系统实现海量文件存储:如采用fastdfs实现海量图片存储,提升文件的访问速度。

采用mq使用服务进一步解藕:同步索引库,同步静态资源,短信发送

            

 服务器层面的优化:

 集群思想的使用:tomcat,zookeeper,redis,mysql等

Tomcat异步通讯的使用,tomcat链接池配置

 

秒杀和团购业务实现思路

回答:

将商品数量查询出存入到redis中,全部用户下单后,减掉redis中的数量

若是并发量很大时,还要考虑高并发问题,因此能够加入mq消息中间件处理抢单问题,再结合redis实现库存减小操做。高并发方面还能够考虑CDN,Nginx负载均衡等

 

大家项目中使用的安全框架是什么

使用springSecurity 或者shiro,校验用户登陆和用户权限!

 

项目中使用到的应用服务器是什么

Tomcat+nginx

 

讲一下每台服务器的集群数量

      项目中一共15台项目服务,那么为了每一台高可用一主一备,但首页项目高并发设为四台服务器,则一共32台项目服务器,再加redis集群用了3台,为了每一台高可用一主一备一共6台,fastdfs一个trackerServer一个storageServer搭建集群一共6台,solr集群7台服务器,nginx为了高可用一主一备一共2台,mysql数据库集群3台!activemq消息中间件高可用2台;

共计:58台服务器!

 

你在项目开发中碰到过哪些重大且棘手的问题

场景一:需求不明确困境

在项目开发中,项目采用迭代开发,开发需求不是很明确,对于项目开发初期来讲很是困难,进度很是慢,有时开发的出的产品结果每每不能令老板满意,或者是甲方满意,项目还须要不停的迭代,修改。

好比说:

在开发商城项目的时候,客户定位是一个综合性的商务平台,能够实如今线第三方商家对接,实现商品的销售

可是并无明确的需求,所以开发全凭借电商的项目经验来实现里面的相关的业务,后期慢慢迭代。 

 

场景二: ES高亮不能显示的问题

前台使用angularJS加载搜索结果,可是发现高亮不能展现。

问题缘由:

angularJS底层使用ajax,异步加载高亮信息返回给页面后,页面没有刷新,就直接显示返回的数据。此时会把全部的数据做为普通的文本数据进行加载。所以就没有高亮的效果。

解决方案:

使用angularJS过滤器过滤文本数据,此时angularJS过滤器把html文本数据解析为浏览器能识别的html标签。高亮就能展现了。

 

场景三:Nginx静态页面服务跳转到购物车跨域问题

在Nginx中部署了静态页面,添加购物车时必须从静态页面跳转到购物车系统,实现购物车添加操做。

因为在静态页面中使用angularJS实现的跳转,发现跳转到购物车系统彻底没有问题,可是并不能跳转回到购物车系统页面。

问题分析:

从静态详情系统跳转到购物车系统,会存在跨域问题,所以不能进行回调函数的数据传递。因此在回调函数中的页面跳转就不能实现。

解决方案:

使用angularJS跨域调用及springmvc跨域配置,解决问题。

 

 场景四:activeMQ存在运行时间长了之后,收不到消息的现象

时间长了就会出现,卡死,新的数据不能从队列接听到。只能重启程序。

解决方案:

1)不要频繁的创建和关闭链接

 JMS使用长链接方式,一个程序,只要和JMS服务器保持一个链接就能够了,不要频繁的创建和关闭链接。频繁的创建和关闭链接,对程序的性能影响仍是很大的。这一点和jdbc仍是不太同样的。

2)Connection的start()和stop()方法代价很高

 JMS的Connection的start()和stop()方法代价很高,不能常常调用。咱们试用的时候,写了个jms的connection pool,每次将connection取出pool时调用start()方法,归还时调用stop()方法,然然后来用jprofiler发现,通常的cpu时间都耗在了这两个方法上。

3)start()后才能收消息

 Connection的start()方法调用后,才能收到jms消息。若是不调用这个方法,能发出消息,可是一直收不到消息。不知道其它的jms服务器也是这样。

4)显式关闭Session

若是忘记了最后关闭Connection或Session对象,都会致使内存泄漏。这个在我测试的时候也发现了。原本觉得关闭了Connection,由这个Connection生成的Session也会被自动关闭,结果并不是如此,Session并无关闭,致使内存泄漏。因此必定要显式的关闭Connection和Session。

5)对Session作对象池

对Session作对象池,而不是Connection。Session也是昂贵的对象,每次使用都新建和关闭,代价也很是高。并且后来咱们发现,原来Connection是线程安全的,而Session不是,因此后来改为了对Session作对象池,而只保留一个Connection。

6) 集群

ActiveMQ有强大而灵活的集群功能,可是使用起来仍是会有不少陷阱

 

场景五:activeMQ存在发出消息太大,形成消息接受不成功

多个线程从activeMQ中取消息,随着业务的扩大,该机器占用的网络带宽愈来愈高。

仔细分析发现,mq入队时并无异常高的网络流量,仅仅在出队时会产生很高的网络流量。

 

最终发现是springjmsTemplateactivemqprefetch机制配合致使的问题。

研究源码发现jmsTemplate实现机制是:每次调用receive()时都会建立一个新的consumer对象,用完即销毁。

正常状况下仅仅会浪费重复建立consumer的资源代价,并不至于产生正常状况十倍百倍的网络流量。

可是activeMQ有一个提升性能的机制prefetch,此时就会有严重的问题。

prefetch机制:
每次consumer链接至MQ时,MQ预先存放许多message到消费者(前提是MQ中存在大量消息),预先存 放message的数量取决于prefetchSize(默认为1000)。此机制的目的很显然,是想让客户端代码用一个consumer反复进行 receive操做,这样可以大量提升出队性能。

此机制与jmsTemplate配合时就会产生严重的问题,每次jmsTemplate.receive(),都会产生1000个消息的网络流量, 可是由于jmsTemplae并不会重用consumer,致使后面999个消息都被废弃。反复jmsTemplate.receive()时,表面上看 不出任何问题,其实网络带宽会形成大量的浪费。


解决方案:

一、若坚持使用jmsTemplate,须要设置prefetch值为1,至关于禁用了activeMQ的prefetch机制,此时感受最健壮, 就算多线程,反复调用jmsTemplate.receive()也不会有任何问题。可是会有资源浪费,由于要反复建立consumer并频繁与服务器进 行数据通讯,但在性能要求不高的应用中也不算什么问题。

二、不使用jmsTemplate,手工建立一个consumer,并单线程反复使用它来receive(),此时能够充分利用prefetch机制。配合多线程的方式每一个线程拥有本身的一个consumer,此时可以充分发挥MQ在大吞吐量时的速度优点。

切记避免多线程使用一个consumer形成的消息混乱。大吞吐量的应用推荐使用方案2,可以充分利用prefetch机制提升系MQ的吞吐性能。

 

商品的价格变化后,如何同步redis中数以百万计的购物车数据。

购物车只存储商品id,到购物车结算页面将会重新查询购物车数据,所以就不会涉及购物车商品价格同步的问题。

 

系统中的钱是如何保证安全的。

在当前互联网系统中钱的安全是头等大事,如何保证钱的安全能够从如下2个方面来思考:

1)钱计算方面

在系统中必须是浮点数计算类型存储钱的额度,不然计算机在计算时可能会损失精度。

2)事务处理方面

在当前环境下,高并发访问,多线程,多核心处理下,很容易出现数据一致性问题,此时必须使用事务进行控制,访问交易出现安全性的问题,那么在分布式系统中,存在分布式事务问题,能够有不少解决方案:

使用 jpa能够解决

使用 tcc 框架能够解决等等。

 

作交易或是金融系统安全性须要从哪些方面考虑?没有用什么第三方能够框架

ip黑白名单,访问日志明细记录,防止重复提交,访问频率控制,分布式锁,数据先后端校验,自动对帐任务处理,互联网金融项目通常状况下,不建议自动重试,最好结合对帐系统,人工进行处理,写好人工处理的接口就好。其余就是控制好数据的一致性了,这个最重要,其次还要保证接口的幂等性,不要重复处理订单。这些是最基本的安全控制了。像这类网站用户的输入数据通常都不会太多,通常敏感词过滤,广告之类的能够忽略,若是有的话还要控制这些。安全框架选shiro 了,在系统中分配好角色就行了,控制好用户的资源访问。其余的用springmvc 就够了

 

订单中的事物是如何保证一致性的。

使用分布式事务来进行控制,保证数据最终结果的一致性。

 

当商品库存数量不足时,如何保证不会超卖。

当库存数量不足时,必须保证库存不能被减为负数,若是不加以控制,库存被减为小于等于0的数,那么这就叫作超卖。

那么如何防止超卖的现象发生呢?

场景一: 若是系统并发要求不是很高

那么此时库存就能够存储在数据库中,数据库中加锁控制库存的超卖现象。

 

场景二:系统的并发量很大

若是系统并发量很大,那么就不能再使用数据库来进行减库存操做了,由于数据库加锁操做自己是以损失数据库的性能来进行控制数据库数据的一致性的。

可是当并发量很大的时候,将会致使数据库排队,发生阻塞。所以必须使用一个高效的nosql数据库服务器来进行减库存。

此时能够使用redis服务器来存储库存,redis是一个内存版的数据库,查询效率至关的高,能够使用watch来监控减库存的操做,一旦发现库存被减为0,立马中止售卖操做。

 

大家系统的商品模块和订单模块的数据库是怎么设计的

商品模块设计:

商品模块一共8张表,整个核心就是模板表。采用模板表为核心的设计方法,来构造商品数据。

订单设计:

订单涉及的表有:

1)      收货人地址

2)      订单信息

3)      订单明细

 

系统中商家活动策划以及上报相关业务流程。

商城系统中有如下活动:

1)      秒杀活动

          a)    后台设置秒杀商品

          b)    设置秒杀开启时间,定时任务,开启秒杀

          c)    秒杀减库存(秒杀时间结束,库存卖完,活动结束)

2)      促销活动

3)      团购活动

4)      今日推荐

以上活动销售记录,统计,使用图形化报表进行统计,能够查看销售状况。

 

涉及到积分积累和兑换商品等业务是怎么设计的

积分累计有2大块:

积分累计:

根据用户购买的商品的价格不一样,没有购买必定价格的商品,获取必定的积分。

积分商城:

积分商城是用户能够使用积分商品换取商品的区域。

 

介绍下电商项目,你以为那些是亮点?

这个项目是为xxx开发的b2b2c类型综合购物平台,主要以销售xxx,电子产品为主要的电子商城网站。

项目的亮点是:

1)项目采用面向服务分布式架构(使用dubbo,zookeeper)

            a)    解耦

            b)    提升项目并发能力

            c)    分担服务器压力

2)项目中使用activeMQ对项目进一步解耦

            a)    提升项目并发能力

            b)    提升任务处理速度

3)       使用微信支付,支付宝支付(本身总结)

4)       使用阿里大鱼发生短信

5)       使用第三方分布式文件系统存储海量文件

6)       Nginx部署静态页面实现动静分离

 

购物车功能作了吗,实现原理说一下?

  1. 加入购物车 
    加入购物车插入到库中一条购物记录,同时插入到缓存中,缓存的key是记录的id 
    未登陆状态 
    用户未登陆时点击加入购物车,将productId ,skuId,buyNum 转换成json存到cookie中(同一件商品不一样的skuId视为两个商品,相同的skuId和productId视为相同商品数量累加),用户登陆成功的时候接收用户的消息将cookie中的商品信息保存到数据库中,而后清空cookie数据(京东)否则会出现登陆成功后删除购物车商品而后退出,购物车中显示问题 
    登陆状态 
    点击加入购物车将long userId,long productId,long skuId,int count 存到库中,相同的productId和skuId 数量累加,不一样的skuId新增一条 
    addToCart(long userId,long skuId,int count); //加入sku到购物车商品
  2. 修改商品数量 
    未登陆状态 
    用户未登陆时,点击加减数量,根据productId和skuId从cooike中将商品数量进行加减,注意校验cooike中的数量不能小于0,不能大于库存数量 
    登陆状态 
    用户登陆状态时,点击加减数量productId和skuId,userId将用户购物车中某个sku的数量增长或减去differ值,注意校验库存数量 
    updateAmount(long userId,skuId,int differ,List selectedSkuIds); //将用户购物车中某个sku的数量增长或减去differ值。此方法更新商品后,会根据selectedSkuIds从新计算一遍购物车价格,返回知足条件的优惠券
  3. 删除购物车记录 
    未登陆状态 
    用户未登陆时,根据productId和skuId删除cookie中的记录 
    deleteCart(long userId,long skuId, List selectedSkuIds); //将某个sku从用户购物车移除。此接品,在清除后台会重复计算selectedSkuIds价格,并会返回选中的sku列表与未选中的sku列表集合。及相应优惠券。 
    登陆状态 
    登陆状态下,直接根据productId和skuId以及userId删除库中数据 
    4购物车列表展现 
    未登陆状态 
    从cookie中取出productId以及skuId列表展现商品信息 
    登陆状态 
    登陆状态下根据用户id查询库中的记录数 
    getCart(long userId,list selectedSkuIds); //查询用户购物车。此接口会从新计算selectedSkuIds,并返回选中与未选中sku列表集合,返回相应的知足条件的优惠券信息。

5.订单提交成功后更新购物车数量以及修改购物车状态 
订单提交成功后接收订单成功消息,更新购物车状态和数量删除缓存记录

6.商品下架后,更新库存状态,显示失效 
商品下架后接收消息修改购物车里的商品状态为失效

 

们的项目上线了吗?这么大的项目怎么没上线?

项目上线问题回答:

1)       项目没有上线

若是你没有作过电商的项目,能够说项目没有上线以前,你离职了,这个一个创业型的公司,或者此项目是给甲方作的项目,你没有参与上线。以此来回避这个问题.

2)       项目上线

项目已经上线了

上线环境:

a)    Centos7

b)    Mysql

c)    Jdk8

d)    Tomcat8

    关于上线,那么面试官必定会问您,上线遇到什么问题没有?

所以必须把项目中遇到的问题准备2个,如下能够做为参考

问题一:(用户非正常流程致使的错误)

用户注册一半就退出来,致使再次注册不成功或者用证件号登录触发空指针异常。

解决办法:一旦输入证件号时,检查数据库的表是否有相应的证件号记录,有则把相关记录所有删掉,从而让他成功注册。空指针异常的解决办法,作非空验证的判断。

问题二:(并发插入,流水号不一致)

   出现大量的主键惟一约束错误,后来想到是产生的预报名号不一样步,致使有可能大并发量时产生多个相同的流水号,插入就会出现主键惟一约束错误。

   解决办法:在数据库里写一个insert的触发器。自动替换掉要插入的主键为 max(key)+1.

问题三:(并发删除,索引失效)

   出现某些表的索引失效,后来发现是插入相同主键屡次以后致使表失效。

  解决办法:设定oracle任务,让数据库每隔12个小时自动重建全部索引。

问题四:(js代码的不细致)

   发现报考志愿显示的专业比原来的少一个。

  解决办法:发现时jsp页面的js少循环一个=号致使的。。。。

问题五:(页面和后台代码太不通用)

    用户需求一旦更改或者程序逻辑有错误后,致使要修改不少页面和后台代码,十分不通用,要从业务逻辑上设计的通用点。改一个,就能等同于改所有。用一些设计模式去解决。
 

 

订单怎么实现的,大家这个功能怎么这么简单?

订单实现:

从购物车系统跳转到订单页面,选择默认收货地址

选择支付方式

购物清单展现

提交订单

订单业务处理:

一个商家一个订单,不一样的仓库发送的货品也是属于不一样的订单。所以会产出不一样的订单号。

订单处理:根据支付的状态进行不一样的处理

1) 在线支付

a)    支付未成功—重新发起支付

b)    支付超时---订单关闭

2) 货到付款 

 

大家这个项目有秒杀吗,怎么实现的?

所谓“秒杀”,就是网络卖家发布一些超低价格的商品,

全部买家在同一时间网上抢购的一种销售方式。通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动。因为商品价格低廉,每每一上架就被抢购一空,有时只用一秒钟。

秒杀商品一般有两种限制:库存限制、时间限制。

需求:

(1)商家提交秒杀商品申请,录入秒杀商品数据,主要包括:商品标题、原价、秒杀价、商品图片、介绍等信息

(2)运营商审核秒杀申请

(3)秒杀频道首页列出秒杀商品(进行中的)点击秒杀商品图片跳转到秒杀商品详细页。

(4)商品详细页显示秒杀商品信息,点击当即抢购实现秒杀下单,下单时扣减库存。当库存为0或不在活动期范围内时没法秒杀。

(5)秒杀下单成功,直接跳转到支付页面(微信扫码),支付成功,跳转到成功页,填写收货地址、电话、收件人等信息,完成订单。

(6)当用户秒杀下单5分钟内未支付,取消预订单,调用微信支付的关闭订单接口,恢复库存。

数据库表分析

Tb_seckill_goods 秒杀商品表

Tb_seckill_order 秒杀订单表

秒杀实现思路

秒杀技术实现核心思想是运用缓存减小数据库瞬间的访问压力!读取商品详细信息时运用缓存,当用户点击抢购时减小redis中的库存数量,当库存数为0时或活动期结束时,同步到数据库。 产生的秒杀预订单也不会马上写到数据库中,而是先写到缓存,当用户付款成功后再写入数据库。

 

大家这个项目用的什么数据库,数据库有多少张表?

项目使用mysql数据库,总共有103张表,其中商品表共计有8张。

 

项目部署作过吗,能不能部署?

作过,能够部署。

项目服务器:集群部署

数据库服务器:集群部署

Nginx集群:负载均衡

 

单点登陆怎么作的,用别人知道原理吗?

在分布式项目中实现session共享,完成分布式系统单点登陆

3)       Cookie中共享ticket

4)       Redis存储session

分布式系统共享用户身份信息session,必须先获取ticket票据,而后再根据票据信息获取redis中用户身份信息。

实现以上2点便可实现session共享。

目前项目中使用的springsecurity + cas 来实现的单点登陆,cas自动产生ticket票据信息,每次获取用户信息,cas将会携带ticket信息获取用户身份信息。

 

支付作了吗,支付宝仍是微信,实现说下?

微信支付:

1)       调用微信支付下单接口

2)       返回支付地址,生成二维码

3)       扫描二维码便可完成支付

问题: 微信支付二维码是咱们本身生成的,所以必须时刻监控微信支付二维码的状态,确保支付成功。

支付宝支付能够参考www.alipay.com

 

缓存及优化方面的面试问题

怎么提升redis缓存利用率

一、从业务场景分析,预计会高频率用到的数据预先存放到redis中,

二、能够定时扫描命中率低的数据,能够直接从redis中清除。

 

怎么实现数据量大、 并发量高的搜索

建立solr索引库,数据量特别大时采用solr分布式集群

 

MySQL索引使用限制

    不要在列上进行运算。
    select * from users where YEAR(adddate)<2007; 将在每一个行上进行运算,这将致使索引失效而进行全表扫描,所以咱们能够改为select * from users where adddate<‘2007-01-01’;
    like语句操做
    若是使用like。like “%aaa%” 不会使用索引而like “aaa%”能够使用索引。
    select * from users where name like '%aaa%'不会使用索引
    select * from users where name like 'aaa%'能够使用索引
    使用短索引
    例如,若是有一个CHAR(255)的列,若是在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不只能够提升查询速度并且能够节省磁盘空间和I/O操做。
    索引不会包含NULL列
    复合索引中若是有一列含有NULL值那么这个组合索引都将失效,通常须要给默认值0或者 ' '字符串
    最左匹配
    不按索引最左列开始查询(多列索引) 例如index(‘c1’, ‘c2’, ‘c3’) ,where ‘c2’ = ‘aaa’ 不使用索引,where ‘c2’ = ‘aaa’ and ‘c3’ = ‘sss’ 不能使用索引。where ‘c1’ = ‘aaa’ and ‘c2’ = ‘bbb’ 能够使用索引
    多列范围查询
    查询中某个列有范围查询,则其右边的全部列都没法使用查询(多列查询)。where c1= ‘xxx’ and c2 like = ‘aa%’ and c3=’sss’ 该查询只会使用索引中的前两列,c3将不能使用到索引,由于like是范围查询。
    检索排序
    一个查询语句中,既有检索又有排序而且是不一样的字段,且这两个列上都有单列索引(独立索引),那么只有其中一个列用到索引,由于查询优化器在作检索和排序中不能同时使用两个不一样的索引
    索引散列度
    经过索引扫描的记录超过了表总行数的30%(估计值),则查询优化器认为全表扫描的效率更高,因此会变成全表扫描查询
    隐式转换
    隐式转换致使的索引失效。好比,表的字段tu_mdn定义为varchar(20),但在查询时把该字段做为number类型当作where条件,这样会致使索引失效. 错误的例子:select * from test where tu_mdn=13333333333; 正确的例子:select * from test where tu_mdn='13333333333’;
 

怎么分词

使用第三方的分词器IKAnalyzer,会按照中国人用此习惯自动分词。

 

seo怎么优化

使用restful,或静态页这样能更好的被搜索引擎收录。

 

怎么加快访问速度

硬件上加大网络带宽、和服务器内存

代码的处理:静态页面、缓存、优化sql、建立索引等方案

 

讲到redis缓存的时候说不清楚

  1. redis中项目中的应用。1.主要应用在门户网站首页广告信息的缓存。由于门户网站访问量较大,将广告缓存到redis中,能够下降数据库访问压力,提升查询性能。2.应用在用户注册验证码缓存。利用redis设置过时时间,当超过指定时间后,redis清理验证码,使过时的验证码无效。3.用在购物车模块,用户登录系统后,添加的购物车数据须要保存到redis缓存中。
  2. 技术角度分析:

内存若是满了,采用LRU算法进行淘汰。

Redis如何实现负载的?采用Hash槽来运算存储值,使用CRC16算法取模运算,来保证负载问题。

Redis缓存穿透问题?将数据查询出来若是没有强制设置空值,而且设置过时时间,减小频繁查询数据库。

 

能讲下redis的具体使用场景吗?使用redis存储长期不改变的数据彻底能够使用也看静态化,那么大家当时是为何会使用redis?

redis在项目中应用:1.主要应用在门户网站首页广告信息的缓存。由于门户网站访问量较大,将广告缓存到redis中,能够下降数据库访问压力,提升查询性能。2.应用在用户注册验证码缓存。利用redis设置过时时间,当超过指定时间后,redis清理验证码,使过时的验证码无效。3.用在购物车模块,用户登录系统后,添加的购物车数据须要保存到redis缓存中。

使用redis主要是减小系统数据库访问压力。从缓存中查询数据,也提升了查询性能,挺高用户体验度。

 

redis中对一个key进行自增或者自减操做,它是原子性的吗?

是原子性的。对于Redis而言,命令的原子性指的是:一个操做的不能够再分,操做要么执行,要么不执行。Redis的操做之因此是原子性的,是由于Redis是单线程的。对Redis来讲,执行get、set以及eval等API,都是一个一个的任务,这些任务都会由Redis的线程去负责执行,任务要么执行成功,要么执行失败,这就是Redis的命令是原子性的缘由。Redis自己提供的全部API都是原子操做,Redis中的事务实际上是要保证批量操做的原子性。

 

大家项目中使用到的数据库是什么?你有涉及到关于数据库到建库建表操做吗?数据库建立表的时候会有哪些考虑呢?

项目中使用的是MySQL数据库,

数据库建立表时要考虑

a、大数据字段最好剥离出单独的表,以便影响性能

b、使用varchar,代替char,这是由于varchar会动态分配长度,char指定为20,即时你存储字符“1”,它依然是20的长度

c、给表创建主键,看到好多表没主键,这在查询和索引定义上将有必定的影响

d、避免表字段运行为null,若是不知道添加什么值,建议设置默认值,特别int类型,好比默认值为0,在索引查询上,效率立显。

e、创建索引,汇集索引则意味着数据的物理存储顺序,最好在惟一的,非空的字段上创建,其它索引也不是越多越好,索引在查询上优点显著,在频繁更新数据的字段上创建汇集索引,后果很严重,插入更新至关忙。

f、组合索引和单索引的创建,要考虑查询实际和具体模式

 

mysql中哪些状况下能够使用索引,哪些状况不能使用索引?mysql索引失效的情形有哪些?

使用索引:

a、 为了快速查找匹配WHERE条件中涉及到列。

b、 若是表有一个multiple-column索引,任何一个索引的最左前缀能够经过使用优化器来查找行

c、 当运行joins时,为了从其余表检索行。MySql能够更有效的使用索引在多列上若是他们声明的类型和大小是同样的话。在这个环境下,VARCHAR和CHAR是同样的若是他们声明的大小是同样的

d、 为了找到 MIN() or MAX()的值对于一个指定索引的列key_col.

总之,就是常常用到的列就最好建立索引。

 

不能使用引用:

    a) 数据惟一性差(一个字段的取值只有几种时)的字段不要使用索引

好比性别,只有两种可能数据。意味着索引的二叉树级别少,可能是平级。这样的二叉树查找无异于全表扫描

b) 频繁更新的字段不要使用索引

好比logincount登陆次数,频繁变化致使索引也频繁变化,增大数据库工做量,下降效率

c) 字段不在where语句出现时不要添加索引,若是where后含IS NULL /IS NOT NULL/ like ‘%输入符%’等条件,不建议使用索引只有在where语句出现,mysql才会去使用索引

d) where 子句里对索引列使用不等于(<>),使用索引效果通常

 

索引失效:

a.若是条件中有or,即便其中有条件带索引也不会使用(这也是为何尽可能少用or的缘由)

  注意:要想使用or,又想让索引生效,只能将or条件中的每一个列都加上索引

  b.对于多列索引,不是使用的第一部分,则不会使用索引

     c.like查询是以%开头

d.若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引

     e.若是mysql估计使用全表扫描要比使用索引快,则不使用索引

 

8,java中的多线程在大家的这个项目当中有哪些体现?

        a,后台任务:如定时向大量(100W以上)的用户发送邮件;按期更新配置文件、任务调度(如quartz),一些监控用于按期信息采集

b,  自动做业处理:好比按期备份日志、按期备份数据库

c, 异步处理:如发微博、记录日志

 

Redis分布式锁理解

实现思想

获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,经过此在释放锁的时候进行判断。

获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。

释放锁的时候,经过UUID判断是否是该锁,如果该锁,则执行delete进行锁释放。

 

Redis怎么设置过时的?项目过程当中,使用了哪种持久化方式

设置过时:

this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS);

持久化方式:Redis默认的RDB方式

 

项目添加Redis缓存后,持久化具体怎么实现的。

RDB:保存存储文件到磁盘;同步时间为15分钟,5分钟,1分钟一次,可能存在数据丢失问题。

AOF:保存命令文件到磁盘;安全性高,修改后当即同步或每秒同步一次。

上述两种方式在咱们的项目中都有使用到,在广告轮播的功能中使用了redis缓存,先从redis中获取数据,无数据后从数据库中查询后保存到redis中

采用默认的RDB方式,在广告轮播的功能中使用了redis缓存,先从redis中获取数据,无数据就从数据库中查询后再保存到redis中

 

项目中有用到过redis,访问redis是经过什么访问的?redis可以存储的数据类型有哪几种?

Redis经过SpringDataRedis访问的.

  Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)

 

怎样进行程序性能调优

       系统性能就是两个事:   

Throughput ,吞吐量。也就是每秒钟能够处理的请求数,任务数。

Latency, 系统延迟。也就是系统在处理一个请求或一个任务时的延迟。

那么Latency越好,能支持的Throughput就会越高。由于Latency短说明处理速度快,因而就能够处理更多的请求。

提升吞吐量:

   分布式集群,模块解藕,设计模式

系统延迟:

       异步通讯

 

数据库设计的面试问题

你有了解mysql的隔离级别吗?mysql默认的隔离级别是什么?

数据库事务的隔离级别有四种,隔离级别高的数据库的可靠性高,但并发量低,而隔离级别低的数据库可靠性低,但并发量高,系统开销小。

  1. READ UNCIMMITTED(未提交读)
  2. READ COMMITTED(提交读)
  3. REPEATABLE READ(可重复读)
  4. SERIALIZABLE(可串行化)

mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读。

 

sql语句中关于查询语句的优化大家是怎么作的?

一、应尽可能避免在 where 子句中使用!=或<>操做符,不然将引擎放弃使用索引而进行全表扫描。

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

三、应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描

四、尽可能避免在 where 子句中使用 or 来链接条件,不然将致使引擎放弃使用索引而进行全表扫描

五、in 和 not in 也要慎用,不然会致使全表扫描

六、应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。

七、应尽可能避免在where子句中对字段进行函数操做,这将致使引擎放弃使用索引而进行全表扫描

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

九、在使用索引字段做为条件时,若是该索引是复合索引,那么必须使用到该索引中的第一个字段做为条件时才能保证系统使用该索引,不然该索引将不会被使 用,而且应尽量的让字段顺序与索引顺序相一致。

十、索引并非越多越好,索引当然能够提升相应的 select 的效率,但同时也下降了 insert 及 update 的效率,由于 insert 或 update 时有可能会重建索引,因此怎样建索引须要慎重考虑,视具体状况而定。

十一、尽量的使用 varchar/nvarchar 代替 char/nchar ,由于首先变长字段存储空间小,能够节省存储空间,其次对于查询来讲,在一个相对较小的字段内搜索效率显然要高些。

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

 

mysql索引失效的场景有哪些?like作模糊查询的时候会失效吗?

1.WHERE字句的查询条件里有不等于号(WHERE column!=…),MYSQL将没法使用索引

2.相似地,若是WHERE字句的查询条件里使用了函数(如:WHERE DAY(column)=…),MYSQL将没法使用索引

3.在JOIN操做中(须要从多个数据表提取数据时),MYSQL只有在主键和外键的数据类型相同时才能使用索引,不然即便创建了索引也不会使用

4.若是WHERE子句的查询条件里使用了比较操做符LIKE和REGEXP,MYSQL只有在搜索模板的第一个字符不是通配符的状况下才能使用索引。好比说,若是查询条件是LIKE 'abc%',MYSQL将使用索引;若是条件是LIKE '%abc',MYSQL将不使用索引。

5.在ORDER BY操做中,MYSQL只有在排序条件不是一个查询条件表达式的状况下才使用索引。尽管如此,在涉及多个数据表的查询里,即便有索引可用,那些索引在加快ORDER BY操做方面也没什么做用。

6.若是某个数据列里包含着许多重复的值,就算为它创建了索引也不会有很好的效果。好比说,若是某个数据列里包含了净是些诸如“0/1”或“Y/N”等值,就没有必要为它建立一个索引。

7.索引有用的状况下就太多了。基本只要创建了索引,除了上面提到的索引不会使用的状况下以外,其余状况只要是使用在WHERE条件里,ORDER BY 字段,联表字段,通常都是有效的。 创建索引要的就是有效果。 否则还用它干嘛? 若是不能肯定在某个字段上创建的索引是否有效果,只要实际进行测试下比较下执行时间就知道。

8.若是条件中有or(而且其中有or的条件是不带索引的),即便其中有条件带索引也不会使用(这也是为何尽可能少用or的缘由)。注意:要想使用or,又想让索引生效,只能将or条件中的每一个列都加上索引

9.若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引

10.若是mysql估计使用全表扫描要比使用索引快,则不使用索引

 

问题二:Like模糊查询,创建索引会失效

项目中关于表结构拆分,大家是业务层面的拆分仍是表结构层面的拆分?

表结构层面的拆分。经过mycat数据库中间件完成数据库分表操做。

业务层面也有拆分,好比商品模块拆分红8张表来实现存储

 

有了解过大数据层面的分库分表吗?以及mysql的执行计划吗?

分库:经过Mycat结点来管理不一样服务器上的数据库,每一个表最多存500万条记录

分表:重直切割,水平切割

MySql提供了EXPLAIN语法用来进行查询分析,在SQL语句前加一个"EXPLAIN"便可。mysql中的explain语法能够帮助咱们改写查询,优化表的结构和索引的设置,从而最大地提升查询效率。

 

有了解过数据库中的表级锁和行级锁吗?乐观锁和悲观锁你有哪些了解?

MySQL的锁机制比较简单,其最显著的特色是不一样的存储引擎支持不一样的锁机制。好比,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);InnoDB存储引擎既支持行级锁( row-level locking),也支持表级锁,但默认状况下是采用行级锁。

MySQL主要的两种锁的特性可大体概括以下:
表级锁: 开销小,加锁快;不会出现死锁(由于MyISAM会一次性得到SQL所需的所有锁);锁定粒度大,发生锁冲突的几率最高,并发度最低。
行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。

 

乐观锁:经过version版本字段来实现

悲观锁:经过for update来实现

 

Mysql优化有没有工具

三个MySQL性能测试工具:The MySQL Benchmark Suite、MySQL super-smack、MyBench。除了第一个为MySQL性能测试工具,其余两个都为压力测试工具。

 

大家项目中使用到的数据库是什么?你有涉及到关于数据库到建库建表操做吗?数据库建立表的时候会有哪些考虑呢?

项目中使用的是MySQL数据库,

数据库建立表时要考虑

a、大数据字段最好剥离出单独的表,以便影响性能

b、使用varchar,代替char,这是由于varchar会动态分配长度,char指定为20,即时你存储字符“1”,它依然是20的长度

c、给表创建主键,看到好多表没主键,这在查询和索引定义上将有必定的影响

d、避免表字段运行为null,若是不知道添加什么值,建议设置默认值,特别int类型,好比默认值为0,在索引查询上,效率立显。

e、创建索引,汇集索引则意味着数据的物理存储顺序,最好在惟一的,非空的字段上创建,其它索引也不是越多越好,索引在查询上优点显著,在频繁更新数据的字段上创建汇集索引,后果很严重,插入更新至关忙。

f、组合索引和单索引的创建,要考虑查询实际和具体模式

 

怎样进行数据库优化

       a,选取最适用的字段

        在建立表的时候,为了得到更好的性能,咱们能够将表中字段的宽度设得尽量小。另一个提升效率的方法是在可能的状况下,应该尽可能把字段设置为NOTNULL,

       b,使用链接(JOIN)来代替子查询(Sub-Queries)

       c,使用联合(UNION)来代替手动建立的临时表

       d,事物:

           a)要么语句块中每条语句都操做成功,要么都失败。换句话说,就是能够保持数据库中数据的一致性和完整性。事物以BEGIN关键字开始,COMMIT关键字结束。在这之间的一条SQL操做失败,那么,ROLLBACK命令就能够把数据库恢复到BEGIN开始以前的状态。

           b) 是当多个用户同时使用相同的数据源时,它能够利用锁定数据库的方法来为用户提供一种安全的访问方式,这样能够保证用户的操做不被其它的用户所干扰。

       e,锁定表

        f,使用外键

              锁定表的方法能够维护数据的完整性,可是它却不能保证数据的关联性。这个时候咱们就能够使用外键。

        g,使用索引

        h,优化的查询语句

 

怎样进行数据库性能调优

一应用程序优化

 (1)把数据库看成奢侈的资源看待,在确保功能的同时,尽量少地动用数据库资源。

 (2)不要直接执行完整的SQL 语法,尽可能经过存储过程实现数据库操做。

 (3)客户与服务器链接时,创建链接池,让链接尽可能得以重用,以免时间与资源的损耗。

 (4)非到不得已,不要使用游标结构,确实使用时,注意各类游标的特性。

二基本表设计优化

  (1)表设计遵循第三范式。在基于表驱动的信息管理系统中,基本表的设计规范是第三范式。

  (2)分割表。分割表可分为水平分割表和垂直分割表两种:水平分割是按照行将一个表分割为多个表。

 (3)引入中间表。

 数据库索引优化

索引是创建在表上的一种数据组织,它能提升访问表中一条或多条记录的特定查询效率。 

汇集索引

  一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序。 

  汇集索引肯定表中数据的物理顺序。

非汇集索引

  一种索引,该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不一样.

 

分布式开发面试问题

 

分布式架构session共享问题,如何在集群里边实现共享。

用了CAS,全部应用项目中若是须要登陆时在web.xml中配置过滤器作请求转发到cas端工做原理是在cas登陆后会给浏览器发送一个票据(ticket),浏览器cookie中会缓存这个ticket,在登陆其余项目时会拿着浏览器的ticket转发到cas,到cas后根据票据判断是否登陆

 

项目中如何配置集群?

配置了redis集群,使用redis3.0版本官方推荐的配置方式

solr集群使用了solrCloud,使用zookeeper关联solrCloud的配置文件

zookeeper也配置了集群

应用层使用Nginx负载均衡

 

对分布式,dubbo,zookeeper说的不太清楚

分布式是从项目业务角度考虑划分项目整个架构。能够将项目基于功能模块划分再分别部署。Dubbo是实现分布式项目部署框架。在zookeeper是dubbo分布式框架的注册中心,管理服务的注册和调用。

 

从前端到后台的实现的过程描述的也不清楚

项目前端采用angularjs框架在controller控制器中完成数据组装和数据展现,在服务层(service)代码完成中后台请求操做。后端基于前端的接口调用,完成数据的增删改查操做。先后端数据交互经过json格式字符串完成。

 

Dubbo为何选择Zookeeper,而不选择Redis

引入了ZooKeeper做为存储媒介,也就把ZooKeeper的特性引进来。

首先是负载均衡,单注册中心的承载能力是有限的,在流量达到必定程度的时候就须要分流,负载均衡就是为了分流而存在的,一个ZooKeeper群配合相应的Web应用就能够很容易达到负载均衡;

资源同步,单单有负载均衡还不够,节点之间的数据和资源须要同步,ZooKeeper集群就自然具有有这样的功能;

命名服务,将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入本身的URL地址,这个操做就完成了服务的发布。 其余特性还有Mast选举,分布式锁等。

 

项目中Zookeeper服务器挂了,服务调用能够进行吗

能够的,消费者在启动时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。

每次调用时,按照本地存储的地址进行调用

 

如何保证dubbo高可用?

1. zookeeper宕机与dubbo直连

在实际生产中,假如zookeeper注册中心宕掉,一段时间内服务消费方仍是可以调用提供方的服务的,实际上它使用的本地缓存进行通信,这只是dubbo健壮性的一种。

dubbo的健壮性表现:

  • 监控中心宕掉不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能经过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另外一台
  • 注册中心所有宕掉后,服务提供者和服务消费者仍能经过本地缓存通信
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者所有宕掉后,服务消费者应用将没法使用,并没有限次重连等待服务提供者恢复

注册中心的做用在于保存服务提供者的位置信息,咱们能够彻底能够绕过注册中心——采用dubbo直连,即在服务消费方配置服务提供方的位置信息。

点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。

xml配置方式

<dubbo:reference id="userService" interface="com.zang.gmall.service.UserService" url="dubbo://localhost:20880" />

注解上直接添加

@Reference(url = "127.0.0.1:20880")   
 UserService userService;

2. 集群下dubbo负载均衡配置

在集群负载均衡时,Dubbo提供了4种均衡策略,如:Random LoadBalance(随机均衡算法)、RoundRobin LoadBalance(权重轮循均衡算法)、LeastAction LoadBalance(最少活跃调用数均衡算法)、ConsistentHash LoadBalance(一致性Hash均衡算法)。缺省时为Random随机调用。

@Reference(loadbalance = "roundrobin")
 UserService userService;

服务方方法级别配置(基于xml配置的权重轮询均衡算法)

<dubbo:service interface="com.zang.gmall.service.UserService" 
<dubbo:method name="getUserAddressList" loadbalance="roundrobin"></dubbo:method>
</dubbo:service>

3. 权重设置

当不设置负载均衡策略,即采用默认的Random LoadBalance(随机均衡算法)时,默认每一个服务的权重相同,咱们能够经过设置权重来分配访问的随机性。

权重默认为100,能够在暴露服务的同时设置

 

4. 服务降级

当服务器压力剧增的状况下,根据实际业务状况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运做或高效运做。

能够经过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略(不调用服务即返回为空 or 调用失败返回为空

 向注册中心写入动态配置覆盖规则:

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));

其中:

  • mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • 还能够改成 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

 经过操做管理控制台也能够方便的进行服务降级

5. 集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。

集群容错模式主要有如下几种:

Failover Cluster

失败自动切换,当出现失败,重试其它服务器。一般用于读操做,但重试会带来更长延迟。可经过 retries="2" 来设置重试次数(不含第一次)。

消费方服务级注解添加(不能到方法级)

Failfast Cluster

快速失败,只发起一次调用,失败当即报错。一般用于非幂等性的写操做,好比新增记录。

Failsafe Cluster

失败安全,出现异常时,直接忽略。一般用于写入审计日志等操做。

Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。一般用于消息通知操做。

Forking Cluster

并行调用多个服务器,只要一个成功即返回。一般用于实时性要求较高的读操做,但须要浪费更多服务资源。可经过 forks="2" 来设置最大并行数。

Broadcast Cluster

广播调用全部提供者,逐个调用,任意一台报错则报错。一般用于通知全部提供者更新缓存或日志等本地资源信息。

集群模式配置方法

在服务提供方和消费方配置集群模式

6. 整合hystrix

Hystrix 旨在经过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具有拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。

spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>1.4.4.RELEASE</version>
   </dependency>

而后在Application类上增长@EnableHystrix来启用hystrix starter:

配置服务提供方:

在Dubbo的Provider上增长@HystrixCommand 配置,这样子调用就会通过Hystrix代理。

配置服务消费方:

对于Consumer端,则能够增长一层method调用,并在method上配置@HystrixCommand 。当调用出错时,会走到 fallbackMethod = "reliable" 的调用里。

@HystrixCommand注解设置的 reliable 调用方法的里的参数要和 method 的参数保持一致。

 

ActiveMq消息被重复消费,丢失,或者不消费怎么办

重复消费:Queue支持存在多个消费者,可是对一个消息而言,只会有一个消费者能够消费。

丢消息:用持久化消息,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭链接致使消息丢失了。

不消费:去ActiveMQ.DLQ里找找

 

怎样解决activeMQ的消息持久化问题

A:持久化为文件

     这个你装ActiveMQ时默认就是这种,只要你设置消息为持久化就能够了。涉及到的配置和代码有

<persistenceAdapter>

<kahaDB directory="${activemq.base}/data/kahadb"/>

</persistenceAdapter>

producer.Send(request, MsgDeliveryMode.Persistent, level, TimeSpan.MinValue);

      B:持久化为MySql

      加载驱动jar,为数据中建立三个数据库表,存储activemq的消息信息

 

若是activeMQ的消息没有发送成功,怎样确保再次发送成功。

        从新传递消息的状况

ActiveMQ在接收消息的Client有如下几种操做的时候,须要从新传递消息:

 1:Client用了transactions(事务),且在session中调用了rollback()

 2:Client用了transactions,且在调用commit()以前关闭

 3:Client在CLIENT_ACKNOWLEDGE的传递模式下,在session中调用了recover()

   确保客户端有几种状态,检测状态,只要提交了那就说明客户端成功!

 

Zookeeper怎样进行服务治理

接受提供者的接口信息和提供者ip地址进行存储,而后管理消费者和提供者之间调用关系!

 

若是activeMQ的服务挂了,怎么办

一、在一般的状况下,非持久化消息是存储在内存中的,持久化消息是存储在文件中的,它们的最大限制在配置文件的<systemUsage>节点中配置。可是,在非持久化消息堆积到必定程度,内存告急的时候,ActiveMQ会将内存中的非持久化消息写入临时文件中,以腾出内存。虽然都保存到了文件里,但它和持久化消息的区别是,重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除。

二、考虑高可用,实现activemq集群。

 

若是zookeeper服务挂了怎么办

  注册中心对等集群,任意一台宕掉后,会自动切换到另外一台

        注册中心所有宕掉,服务提供者和消费者仍能够经过本地缓存通信

服务提供者无状态,任一台宕机后,不影响使用

服务提供者所有宕机,服务消费者会没法使用,并没有限次重连等待服务者恢复

 

Dubbo有3次重试,假如新消息被重复消费怎么处理

一、去掉超时重试机制

二、服务端增长幂等校验,服务器加入校验机制,若是这个消息已被 消费就再也不重复消费

 

MQ消费者接收不到消息怎么办。

Mq消费者接受不到消息存在2中状况:

1. 处理失败 指的是MessageListener的onMessage方法里抛出RuntimeException。

2. Message头里有两个相关字段:Redelivered默认为false,redeliveryCounter默认为0。

3. 消息先由broker发送给consumer,consumer调用listener,若是处理失败,本地redeliveryCounter++,给broker一个特定应答,broker端的message里redeliveryCounter++,延迟一点时间继续调用,默认1s。超过6次,则给broker另外一个特定应答,broker就直接发送消息到DLQ。

4. 若是失败2次,consumer重启,则broker再推过来的消息里,redeliveryCounter=2,本地只能再重试4次即会进入DLQ。

5. 重试的特定应答发送到broker,broker即会在内存将消息的redelivered设置为true,redeliveryCounter++,可是这两个字段都没有持久化,即没有修改存储中的消息记录。因此broker重启时这两个字段会被重置为默认值。

 

系统的高并发问题是怎么解决的。

并发问题高,这个问题的解决方案是一个系统性的,系统的每一层面都须要作优化:

1)      数据层

a)    集群

b)    分表分库

c)    开启索引

d)    开启缓存

e)    表设计优化

f)     Sql语句优化

g)    缓存服务器(提升查询效率,减轻数据库压力)

h)    搜索服务器(提升查询效率,减轻数据库压力)

2)      项目层

a)    采用面向服务分布式架构(分担服务器压力,提升并发能力)

b)    采用并发访问较高的详情系统采用静态页面

c)    使用页面缓存

d)    用ActiveMQ使得业务进一步进行解耦,提升业务处理能力

e)    使用分布式文件系统存储海量文件

3)      应用层

a)    Nginx服务器来作负载均衡

b)    Lvs作二层负载

 

并发数多少,项目中怎么解决并发问题?

       面试中项目的并发数不宜说的过大,安装目前谷粒商城项目拆分规模,这个项目的并发是在10000+,可是学生面试不能说的这么高。

 

能够有如下2方面的回答:

1)    项目并发并不清楚(只是底层程序员)

2)    参与核心业务设计,知道并发是多少(测试峰值,上线并发)

3000---5000吧

面对项目高并发,项目必须作各类优化措施了:

4)      数据层

a)    集群

b)    分表分库

c)    开启索引

d)    开启缓存

e)    表设计优化

f)     Sql语句优化

g)    缓存服务器(提升查询效率,减轻数据库压力)

h)    搜索服务器(提升查询效率,减轻数据库压力)

5)      项目层

a)    采用面向服务分布式架构(分担服务器压力,提升并发能力)

b)    采用并发访问较高的详情系统采用静态页面

c)    使用页面缓存

d)    用ActiveMQ使得业务进一步进行解耦,提升业务处理能力

e)    使用分布式文件系统存储海量文件

6)      应用层

a)    Nginx服务器来作负载均衡

b)    Lvs作二层负载

 

消息发送失败怎么处理,发送数据,数据库已经保存了数据,可是redis中没有同步,怎么办。或者说如何作到消息同步。

消息发送失败,能够进行消息的从新发送,能够配置消息的重发次数。

若是消息重发完毕后,消息尚未接受成功,重启服务。

 

Dubbo的通讯原理?

Dubbo底层使用hessain2进行二进制序列化进行远程调用

Dubbo底层使用netty框架进行异步通讯。NIO

 

 

其余技术面试问题

单点登陆的访问或者跨域问题

首先要理解什么是单点登陆。单点登陆是相互信任的系统模块登陆一个模块后,其余模块不须要重复登陆即认证经过。项目采用的是CAS单点登陆框架完成的。首先CAS有两大部分。客户端和服务端。服务端就是一个web工程部署在tomcat中。在服务端完成用户认证操做。每次访问系统模块时,须要去CAS完成获取ticket。当验证经过后,访问继续操做。对于CAS服务端来讲,咱们访问的应用模块就是CAS客户端。

 

跨域问题,首先明白什么是跨域。何时涉及跨域问题。当涉及前端异步请求的时候才涉及跨域。那什么是跨域呢?当异步请求时,访问的请求地址的协议、ip地址、端口号任意一个与当前站点不一样时,就会涉及跨域访问。解决方案:一、jQuery提供了jsonp实现二、W3C标准提供了CORS(跨域资源共享)解决方案。

 

shiro安全认证时如何作的

要明白shiro执行流程以及shiro的核心组件

认证过程:

在application Code应用程序中调用subject的login方法。将页面收集的用户名和密码传给安全管理器securityManager,将用户名传给realm对象。Realm对象能够理解为是安全数据桥,realm中认证方法基于用户名从数据库中查询用户信息。若是用户存在,将数据库查询密码返回给安全管理器securityManager,而后安全管理器判断密码是否正确。

 

ES的用途

ES在系统中主要完成商品搜索功能,提升搜索性能。

 

分布式锁的问题

针对分布式锁的实现,目前比较经常使用的有如下几种方案:

1.基于数据库实现分布式锁

2.基于缓存(redis,memcached,tair)实现分布式锁

3.基于zookeeper实现分布式锁

 

ES索引中使用了IK分词器,大家项目中使用到了分词器的哪一种工做模式?

IK分词器,基本可分为两种模式,一种为smart模式,一种为非smart模式。

例如:张三说的确实在理
smart模式的下分词结果为:
张三 | 说的 | 确实 | 在理
而非smart模式下的分词结果为:
张三 | 三 | 说的 | 的确 | 的 | 确实 | 实在 | 在理
可见非smart模式所作的就是将可以分出来的词所有输出;smart模式下,IK分词器则会根据内在方法输出一个认为最合理的分词结果,这就涉及到了歧义判断。

项目中采用的是smart模块分词的。

 

java中关于多线程的了解你有多少?线程池有涉及吗?

同一类线程共享代码和数据空间,每一个线程有独立的运行栈和程序计数器(PC),线程切换开销小。线程分为五个阶段:建立、就绪、运行、阻塞、终止。

Java线程有五种基本状态

新建状态(New):当线程对象对建立后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经作好了准备,随时等待CPU调度执行,并非说执行了t.start()此线程当即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的惟一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程因为某种缘由,暂时放弃对CPU的使用权,中止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的缘由不一样,阻塞状态又能够分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 -- 线程在获取synchronized同步锁失败(由于锁被其它线程所占用),它会进入同步阻塞状态;
3.其余阻塞 -- 经过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

 

Java中线程的建立常见有如三种基本形式
1.继承Thread类,重写该类的run()方法。

2.实现Runnable接口,并重写该接口的run()方法,

该run()方法一样是线程执行体,建立Runnable实现类的实例,并以此实例做为Thread类的target来建立Thread对象,该Thread对象才是真正的线程对象。

3.使用Callable和Future接口建立线程。

具体是建立Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象做为Thread对象的target来建立线程。

线程池:线程池是一种多线程处理形式,处理过程当中将任务添加到队列,而后在建立线程后自动启动这些任务。线程池线程都是后台线程。每一个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。若是某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另外一个辅助线程来使全部处理器保持繁忙。若是全部线程池线程都始终保持繁忙,但队列中包含挂起的工做,则线程池将在一段时间后建立另外一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程能够排队,但他们要等到其余线程完成后才启动。

 

如何实现线程的同步?

为什么要使用同步? 

   java容许多线程并发控制,当多个线程同时操做一个可共享的资源变量时(如数据的增删改查),将会致使数据不许确,相互之间产生冲突,所以加入同步锁以免在该线程没有完成操做以前,被其余线程的调用,从而保证了该变量的惟一性和准确性。

线程同步(5种同步方式)

1.同步方法  2.同步代码块   3.使用特殊域变量(volatile)实现线程同步  4.使用重入锁实现线程同步  5.使用局部变量实现线程同步 

 

遍历hashmap有几种方式?

Map的四种遍历方式

(1) for each map.entrySet()

(2) 显示调用map.entrySet()的集合迭代器

(3) for each map.keySet(),再调用get获取

(4) for each map.entrySet(),用临时变量保存map.entrySet()

 

简单介绍一下Es全文检索在整个系统中的应用,在更新索引库的同时会产生索引碎片,这个碎片是如何处理的?

根据商品的名称,分类,品牌等属性来建立索引进行商品搜索。

更新索引库时会先删除索引,而后再重建。而对于删除汇集索引,则会致使对应的非汇集索引重建两次(删除时重建,创建时再重建).直接删除碎片。

 

java并发包下有哪些并发组件?

分为两层组成

    外层框架主要有Lock(ReentrantLock、ReadWriteLock等)、同步器(semaphores等)、阻塞队列(BlockingQueue等)、Executor(线程池)、并发容器(ConcurrentHashMap等)、还有Fork/Join框架; 

内层有AQS(AbstractQueuedSynchronizer类,锁功能都由他实现)、非阻塞数据结构、原子变量类(AtomicInteger等无锁线程安全类)三种。

 

讲一下jvm调优。

     a,堆大小设置

     b,回收器选择

     c,辅助信息

        JVM提供了大量命令行参数,打印信息,供调试使用;

 

讲一下jvm的组成。

      JVM 由类加载器子系统、运行时数据区、执行引擎以及本地方法接口组成

 

讲一下ThreadLocal类。

ThreadLocal,不少地方叫作线程本地变量,也有些地方叫作线程本地存储,其实意思差很少。可能不少朋友都知道ThreadLocal为变量在每一个线程中都建立了一个副本,那么每一个线程能够访问本身内部的副本变量;

ThreadLocal在每一个线程中对该变量会建立一个副本,即每一个线程内部都会有一个该变量,且在线程内部任何地方均可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。

可是要注意,虽然ThreadLocal可以解决上面说的问题,可是因为在每一个线程中都建立了副本,因此要考虑它对资源的消耗,好比内存的占用会比不使用ThreadLocal要大;

 

怎么确保session共享?

在分布式项目中实现session共享必须作如下准备工做:

1)       Cookie中共享ticket

2)       Redis存储session

分布式系统共享用户身份信息session,必须先获取ticket票据,而后再根据票据信息获取redis中用户身份信息。

实现以上2点便可实现session共享。

 

目前项目中使用的springsecurity + cas 来实现的单点登陆,cas自动产生ticket票据信息,每次获取用户信息,cas将会携带ticket信息获取用户身份信息。

 

项目中哪块涉及了线程问题,怎么处理的?

项目的高并发访问就是一个多线程问题。

项目中普通的业务开发基本没有涉及多线程问题,不过你能够谈谈你使用的框架中使用的多线程技术:

由于咱们项目使用的框架进行开发的,所以多线程处理多让框架非咱们处理结束了。

1)       高并发就是多线程,这里的多线程让servlet服务器给处理了谈谈Tomcat多线程配置;

a)   配置线程池,扩大并发能力

b)  开启NIO能力等等

2)       框架多线程:mybatis 框架底层使用的链接池

相关文章
相关标签/搜索