目录

电商系统开发面试知识点 6

1.描述一下你的项目 6

2.描述一下你的系统架构 6

3.说一下dubbox的使用方法。 7

4.持久层框架为什么选择mybatis? 7

5.电商项目中会有很多图片需要保存,你们系统中是如何保存图片的? 7

6.你们系统的并发是多少?如何解决高并发的问题? 8

7.你们商城是否做过seo处理。是如何做的? 8

8.网页静态化的实现方案。 8

9.你们项目中是redis做缓存,你redis存的是什么格式的数据,是怎么存的? 9

10.你们项目中缓存的应用场景? 9

11.如何提高缓存的利用率? 9

12.项目中使用到了缓存,那么如何实现缓存同步的? 10

13.Redis是nosql数据库,是否适合存储大数据? 10

15如何处理数据量大、并发量高的搜索? 10

16.你们项目搜索功能中是如何处理分词的?新上市的商品如何处理分词? 11

17.你们的项目中的系统之间是如何通信的? 11

18.项目中是否使用消息中间(MQ)件进行通信?有什么好处? 11

19.Activemq有几种消息通信方式? 11

20.Activemq在你项目中的应用场景是什么? 11

21.如何处理集群环境下的登录问题。 12

22.你的项目中购物车是如何实现的? 12

23.搞活动秒杀抢购时库存是如何控制的? 12

24.你们商城的支付系统是如何实现的? 12

25.angularJS包括哪些常用指令? 12

26.你们使用什么技术实现数据的缓存? 13

27.如何实现负载均衡? 13

28.当数据库的数据特别大,如何实现扩容? 13

29.什么是mysql数据库的读写分离? 13

30.什么是Docker? 14

31.如果用户一直添加购物车添加商品怎么办?并且他添加一次你查询一次数据库?互联网上用户那么多,这样会对数据库造成很大压力你怎么办? 14

32.dubbo服务开发流程,运行流程?zookeeper注册中心的作用? 14

34.acitveMQ的作用、原理?(生产者。消费者。 p2p、订阅实现流程) 15

35.activeMQ如果数据提交不成功怎么办? 15

36.单点登录系统,如果cookie禁用,你们怎么解决? 15

37.商品存入数据库怎么保证数据库数据安全? 16

Redis 16

1.Redis 的数据结构都有哪些。 16

3.Redis 的并发竞争问题如何解决,了解 Redis 事务的 CAS 操作吗。 17

4.redis集群怎么连接 17

5.Redis5种数据类型,常用命令 17

6.本网站外部的子网站怎么实现单点登录 18

7.说说你用了redis缓存,你redis存的是什么格式的数据,是怎么存的 18

8.你前台portal采用4台服务器集群部署,那能前台高并发访问性能提上去了,那数据库会不会造成一个瓶颈,这一块你是怎么处理的 18

9.你购物车存cookie里边 可以实现不登录就可以使用购物车 那么我现在没有登录把商品存购物车了 然后登录了 然后我换台电脑并且登录了还能不能看见我购物车的信息?如果看不到怎么做到cookie同步,就是在另外一台电脑上可以看到购物车信息 18

10.redis为什么可以做缓存?项目中使用redis的目的是什么?redis什么时候使用? 19

11.Redis 的优点? 19

12.Redis 的缺点? 19

14.redis缓存会出现什么问题? 20

15.redis适合缓存怎么样的数据? 20

16.缓存的同步机制,数据更新后怎么办 20

dubbo 21

  1. 什么是存储过程?它有什么优点? 23

  2. oracle的存储过程和函数有什么区别? 23

  3. 什么是事务? 24

  4. 什么是索引?它有什么优点? 24

  5. 什么是触发器,它有哪些优点?说说你遇到过的常见应用? 24

  6. 触发器分为事前触发和事后触发的区别。语句级触发和行级触发有何区别? 25

  7. 视图是什么?游标是什么? 25

  8. 怎么优化数据库(在数据百万条记录的数据库中 Oracle)? 25

  9. 如何优化SQL语句 25

  10. 使用索引查询一定能提高查询的性能吗?为什么? 26

  11. 操作符优化 26

  12. 说说你知道的一些关于查询优化的方案? 27

  13. 谈谈你对SQL海量数据查询优化性能的一些看法? 29

  14. 数据库内联与外联的区别? 29

  15. 数据库中,我们对主键有哪些要求? 30

  16. 分别说说MySQL和oracle的分页? 30

19.数据库会死锁吗,举一个死锁的例子,mysql 怎么解决死锁。 30

Nginx 31

1.简述Nginx集群和作用 31

2.niginx负载均衡有哪几种方式 31

3.简述Nginx 与 Apache的区别 31

1.1、nginx相对于apache的优点: 31

4.Nginx反向代理为什么可以提高网站性能? 32

5.Httpclient是什么 33

6.jsonp是什么? 33

基础 33

1.Java 中会存在内存泄漏吗,请简单描述。 33

2.阐述静态变量和实例变量的区别。 33

3.如何实现对象克隆? 33

4.GC是什么?为什么要有GC? 34

5.String s = new String(“xyz”);创建了几个字符串对象? 34

6.数据类型之间的转换: 34

7.try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后? 35

8.Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用? 35

9.阐述ArrayList、Vector、LinkedList的存储性能和特性。 35

10List、Map、Set三个接口存取元素时,各有什么特点? 36

11Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别? 36

12线程的sleep()方法和yield()方法有什么区别? 36

13编写多线程程序有几种实现方式? 37

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

15、什么是线程池(thread pool)? 37

16.如何通过反射创建对象? 37

17.如何通过反射获取和设置对象私有字段的值? 38

18.简述一下你了解的设计模式。 38

19.转发(forward)和重定向(redirect)的区别? 39

20.get和post请求的区别? 39

21.JSP和Servlet是什么关系? 39

22.如何实现JSP或Servlet的单线程模式? 40

集合 40

1.ArrayList 和 LinkedList 有什么区别。 40

2.ArrayList 底层实现方式? 40

3.LinkedList 底层实现方式? 41

4.HashSet的底层实现方式? 41

5.HashMap的底层实现之扩容? 41

6.Hashtable的底层实现之扩容? 41

7.ArrayList 集合加入11万条数据,应该怎么提高效率? 42

8.以下是关于HashMap 面试题 42

8.1你用过 HashMap 吗?什么是 HashMap?你为什么用到它? 42

8.2你知道 HashMap的工作原理吗? 你知道 HashMap 的get()方法的工作原理吗? 42

8.3当两个对象的 hashcode 相同会发生什么? 42

8.4如果 HashMap 的大小超过了负载因子(load factor)定义的容量,怎么办? 43

8.5 HashMap 的工作原理 43

8.6 HashMap和Hashtable 的区别 43

8.7 HashSet和HashMap 的区别 44

品优购电商系统开发面试知识点
1.描述一下你的项目
品优购网上商城是一个综合性的B2B2C平台,类似京东商城。商家可以申请入驻到平台进行商品的销售,会员可以在商城浏览商品、搜索商品、使用购物车、购买商品下订单,以及参加秒杀团购等各种活动。网站前台共分为门户、搜索、商品详情页、购物车、秒杀、用户中心、单点登陆系统等7个模块。

系统有两个管理后台:商家管理后台和运营商管理后台。 商家申请入驻后,即可获得商家管理后台的使用权限,在商家管理后台可以提交商品信息、品牌申请、规格申请等。商家提交的商品信息必须经过管理员在运营商管理后台进行审核方可正式销售 。管理员、运营人员可以在运营商后台管理系统中审核商家入驻申请、审核商品提交申请、管理订单、会员、商家结算、统计分析等,客服可以在运营商后台管理系统中处理用户的询问以及投诉。

2.描述一下你的系统架构
品优购网上商城采用当前最流行的SSM(springmvc+spring+mybatis)框架开发,是当前电商网站首选的技术架构。系统是基于SOA架构设计,采用当当的dubbox作为服务中间件,前端采用angularJS + Bootstrap,操作简便用户体验好。商品详细页使用freemarker做静态化页面来提高系统的性能,使用nginx做负载均衡服务器以应对大规模的用户量的并发。电商搜索系统采用当前最流行的全文检索技术solr集群实现。系统中使用redis集群做缓存,使用Activemq做消息中间件。后台数据库使用mysql数据库,使用mycat做读写分离。

3.说一下dubbox的使用方法。

Dubbox是一个分布式服务框架,提供了统一的高性能的远程服务调用平台。所有的业务逻辑都使用dubbox发布供表现层工程调用。发布dubbox服务需要使用spring容器的支持来发布服务,调用服务同样使用spring容器来应用服务。其中服务的发布和服务的发现都是通过注册中心来实现,我们使用zookeeper作为注册中心。

4.持久层框架为什么选择mybatis?
互联网项目追求的是高性能,尤其是数据库查询的时候,在并发量高的情况下需要对sql语句进行调优。Mybatis就是面向sql语句的,所以操作起来笔记容易入手。所以一般互联网项目中大多采用mybatis作为持久层框架。

5.电商项目中会有很多图片需要保存,你们系统中是如何保存图片的?
在电商项目中需要保存大量的图片,需要一个独立的图片服务器来保存,而且存储的容量需要可扩展。并且还需要解决在高并发及高可用的问题。所以我们采用一个FastDFS一个分布式文件系统来保存图片。FastDFS可以搭建服务器集群,解决了存储空间的水平扩展、负载均衡以及服务器的高可用问题。

6.你们系统的并发是多少?如何解决高并发的问题?
经过我们对系统的调优,保证压力测试时每个tomcat的并发量达到400。现在我们有5台web服务器提供服务,基本上也就是2000左右的并发,如果将来并发量进一步提高是可以再增加服务器来提供并发能力。

解决高并发问题首先要提高本系统的吞吐能力,例如在系统中添加缓存、实现网页静态化等方式。如果在系统优化之后还不能满足业务的需要就需要增加服务器,做服务器集群。前端使用nginx做负载均衡服务器,并实现nginx的高可用。目前可以满足当前的业务需要,如果将来业务量增加的话可以考虑添加服务器及F5硬负载等设备。

7.你们商城是否做过seo处理。是如何做的?
我们做过seo处理,也就是配合seo人员做一些工作。在页面中添加一个关键词、做网页的伪静态化或者是纯静态化等处理。还有就是在页面的关键词中中添加一些链接等。

8.网页静态化的实现方案。
创建一个独立的工程,此功能的功能就是生成静态化页面的,例如商品详情页面静态化。将此工程独立部署到一个服务上,页面就生成到当前服务的磁盘上,并且此工程监听MQ的消息,一旦后台工程添加商品,此工程将接收到消息并且生成静态页面。在此服务器上安装一个nginx做为访问静态资源的http服务器。

9.你们项目中是redis做缓存,你redis存的是什么格式的数据,是怎么存的?
Redis提供的存储形式比较丰富。为了便于对缓存数据进行管理,我们多数是采用hash(键值对)格式来存储的。

10.你们项目中缓存的应用场景?
在商城系统中当并发量比较高,频繁的对数据库进行读操作的时候都需要添加缓存。例如页面中广告数据、搜索面板数据、购物车等。

11.如何提高缓存的利用率?
做数据的缓存时,因为数据量很大,而且缓存是把数据保存到内存中,此时不可能把所有的数据都放到缓存中。所以需要设置数据缓存的有效期,当用户访问到非热点数据后,此数据放到缓存中,当缓存到期后就从缓存中删除,而且长时间不会添加到缓存。而热点数据一旦从缓存中删除会马上又添加到缓存。这样可以提高缓存的利用率,同时也减轻了数据库的压力。

12.项目中使用到了缓存,那么如何实现缓存同步的?
只要使用了缓存就涉及到缓存同步的问题。缓存同步其实就是当缓存的信息发生变化,也就是对后台对缓存的数据进行增、删、改操作后,数据库中的数据发生了变化同时要把缓存中的数据对应删除即可。当页面再次请求数据时,缓存中不能命中就会从数据库中查询并且添加到缓存中,即实现了缓存同步。

13.Redis是nosql数据库,是否适合存储大数据?
Redis是nosql数据库,但是redis是key-value形式的nosql数据库,数据是存储到内存中的,适合于快速存取一般作为缓存使用。所以不适合于大数据的存储。并且redis是单线程的如果某个操作进行大数据的存储的话其他的进程都处于等待状态,这样就降低了性能。所以在redis中不适合于大数据的存储。如果是类似商品评论这样的价值不高的大批量数据,我们的做法是采用mongodb。

14.你们系统中搜索是怎么实现的?

电商搜索一般也是使用全文检索实现,我们使用的是solr作为全文检索服务器,实现搜索功能。我们在solr中配置跟业务相关的业务域,从数据库中把相关的数据导入到索引库中。例如商品搜索功能就把商品表中的数据导入到索引库中。然后使用solr实现商品搜索,然后在页面中把搜索结果展示出来。

我们把SKU商品名称、商家名称、价格、规格等信息设置为业务域。规格的存储采用了动态域来实现。

我们使用的是SpringDataSolr框架来实现对solr的操作。

15如何处理数据量大、并发量高的搜索?
如果要搜索的内容数据量很大并且并发量很高的情况下,一个solr服务是不能满足要求的,所以此时需要SolrCloud来解决。SolrCloud也就是solr的分布式解决方案。是zookeeper+solr实现的。

16.你们项目搜索功能中是如何处理分词的?新上市的商品如何处理分词?
在项目中搜索功能使用solr实现,在solr中配置中文分析器,我们使用IKAnalyzer来实现中文分词。如果是新上市的商品可能会出现一些新的关键词,为了查询的准确性,我们会把新的关键词添加到IKAnalyzer的扩展词典中。

17.你们的项目中的系统之间是如何通信的?
我们项目主体部分采用的是Dubbox分布式框架,利用Zookeeper实现各系统之间的调用。另外就是使用ActiveMQ实现系统之间异步调用。前端跨域调用使用CORS技术。

18.项目中是否使用消息中间(MQ)件进行通信?有什么好处?
项目中使用到了Activemq,可以实现系统之间的异步通信,从而实现业务的解耦和执行效率的提升。

19.Activemq有几种消息通信方式?
使用MQ中间件可以有两种通信方式queue和topic。Queue可以实现点到点之间的通信,可以有多个Producer也可以有多个Consumer,但是消息只能被一个Consumer接收,一旦消息被消费后就没有了。

Topic可以实现类似广播的通信方式,可以有多个Producer和多个Consumer,一旦有Producer发送消息后,此消息可以被所有Consumer接收。

20.Activemq在你项目中的应用场景是什么?
应用场景1:当后台系统对商品数据进行添加、删除、修改后,将会发送一个消息变化的消息,此消息通过topic进行通信,有多个消费端,:商品详情页面的静态页面会重新生成。

应用场景2:用户注册时,向用户注册发送短信验证码,采用queue方式通信。消费端调用阿里大于短信接口进行短信的发送。

21.如何处理集群环境下的登录问题。
在我们的项目中,我们使用一个SSO(单点登录)系统来解决集群环境下的登录问题,只需要在单点登录系统中登录一次就可以访问其他的互信,网站。我们采用的耶鲁大学的开源项目CAS,并与SpringSecurity进行集成 。

22.你的项目中购物车是如何实现的?
我们的项目中是用户不登陆的时候也可以使用购物车,通过读写cookie实现的。当用户登陆后,将本地的购物车同步到服务端,采用Redis进行存储。同步后将本地的购物车数据清除。

23.搞活动秒杀抢购时库存是如何控制的?
1、把商品的数量放到redis中。

2、秒杀时使用decr命令对商品数量减一。如果不是负数说明抢到。

3、一旦返回数值变为0说明商品已售完。

24.你们商城的支付系统是如何实现的?
我们系统采用微信扫码支付。首先需要到微信平台申请微信公众账号(服务号),然后再申请开通微信支付。开通后会得到appid、秘钥等数据,用于调用微信支付接口。

微信支付接口是通过httpClient方式向微信支付平台发送数据并获取结果。

(1)调用统一下单接口获取url

(2)根据获取的url在页面上通过qrcode.js生成二维码

(3)生成二维码后,实时轮询查询订单状态,当返回成功时,跳转至成功页面

25.angularJS包括哪些常用指令?
ng-app 指定应用模块

ng-controller 指定控制器

ng-init 指定控制器调用的初始化方法

ng-model 绑定变量

ng-if 条件判断

ng-repeat 循环数据

26.你们使用什么技术实现数据的缓存?
我们使用redis作为数据缓存,并搭建redis集群(6个点,3主3备),使用Spring Data Redis框架操作redis缓存。

27.如何实现负载均衡?
可以使用nginx做反向代理服务器,经过配置nginx.conf 配置反向代理,将请求转发给后端的tomcat集群 ,实现负载均衡。

28.当数据库的数据特别大,如何实现扩容?
数据库可以实现垂直切分和水平节分。垂直切分就是将不同业务模块的表存入到不同的数据库中。水平切分就是将一个表的数据按照一定分片规则存储在不同的数据库中。

我们可以使用mycat数据库中间件。Mycat可以很方便地管理数据的集群。通过设置数据节点、分片规则、逻辑库、逻辑表来实现数据的水平切分。

29.什么是mysql数据库的读写分离?
对于大部分应用,数据库读的多,写的少。数据库所承担是主要是读的压力。我们可以通过mysql的主从复制实现数据库的读写分离。即一个主库(用于写入数据),多个从属库(用于读取数据)。当用户发送查询语句,就访问从属库,如果用户发送增删改语句,就访问主库。

主库与从属库之间建立心跳,实现实时同步数据。

30.什么是Docker?
Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署。

31.如果用户一直添加购物车添加商品怎么办?并且他添加一次你查询一次数据库?互联网上用户那么多,这样会对数据库造成很大压力你怎么办?
当前我们使用cookie的方式来保存购物车的数据,所以当用户往购物车中添加商品时,并不对数据库进行操作。将来把购物车商品放入redis中,redis是可以持久化的可以永久保存,此时就算是频繁的往购物车中添加数据也没用什么问题。

32.dubbo服务开发流程,运行流程?zookeeper注册中心的作用?
使用流程:

第一步:要在系统中使用dubbo应该先搭建一个注册中心,一般推荐使用zookeeper。

第二步:有了注册中心然后是发布服务,发布服务需要使用spring容器和dubbo标签来发布服务。并且发布服务时需要指定注册中心的位置。

第三步:服务发布之后就是调用服务。一般调用服务也是使用spring容器和dubbo标签来引用服务,这样就可以在客户端的容器中生成一个服务的代理对象,在action或者Controller中直接调用service的方法即可。

Zookeeper注册中心的作用主要就是注册和发现服务的作用。类似于房产中介的作用,在系统中并不参与服务的调用及数据的传输。

33.redis为什么可以做缓存?项目中使用redis的目的是什么?redis什么时候使用?

1)Redis是key-value形式的nosql数据库。可以快速的定位到所查找的key,并把其中的value取出来。并且redis的所有的数据都是放到内存中,存取的速度非常快,一般都是用来做缓存使用。

2)项目中使用redis一般都是作为缓存来使用的,缓存的目的就是为了减轻数据库的压力提高存取的效率。

3)在互联网项目中只要是涉及高并发或者是存在大量读数据的情况下都可以使用redis作为缓存。当然redis提供丰富的数据类型,除了缓存还可以根据实际的业务场景来决定redis的作用。例如使用redis保存用户的购物车信息、生成订单号、访问量计数器、任务队列、排行榜等。

34.acitveMQ的作用、原理?(生产者。消费者。 p2p、订阅实现流程)
Activemq的作用就是系统之间进行通信。当然可以使用其他方式进行系统间通信,如果使用Activemq的话可以对系统之间的调用进行解耦,实现系统间的异步通信。原理就是生产者生产消息,把消息发送给activemq。Activemq接收到消息,然后查看有多少个消费者,然后把消息转发给消费者,此过程中生产者无需参与。消费者接收到消息后做相应的处理和生产者没有任何关系。

35.activeMQ如果数据提交不成功怎么办?
Activemq有两种通信方式,点到点形式和发布订阅模式。如果是点到点模式的话,如果消息发送不成功此消息默认会保存到activemq服务端知道有消费者将其消费,所以此时消息是不会丢失的。

如果是发布订阅模式的通信方式,默认情况下只通知一次,如果接收不到此消息就没有了。这种场景只适用于对消息送达率要求不高的情况。如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅是向activemq注册。发布消息和接收消息时需要配置发送模式为持久化。此时如果客户端接收不到消息,消息会持久化到服务端,直到客户端正常接收后为止。

36.单点登录系统,如果cookie禁用,你们怎么解决?
如果禁用cookie可以使用url中带参数,把token传递给服务端。当然此方法涉及安全性问题,其实在cookie中保存token同样存在安全性问题。推荐使用sso框架CAS实现单点登录。

37.商品存入数据库怎么保证数据库数据安全?
1)对用户安全管理

用户操作数据库时,必须通过数据库访问的身份认证。删除数据库中的默认用户,使用自定义的用户及高强度密码。

2)定义视图

为不同的用户定义不同的视图,可以限制用户的访问范围。通过视图机制把需要保密的数据对无权存取这些数据的用户隐藏起来,可以对数据库提供一定程度的安全保护。实际应用中常将视图机制与授权机制结合起来使用,首先用视图机制屏蔽一部分保密数据,然后在视图上进一步进行授权。

3)数据加密

数据加密是保护数据在存储和传递过程中不被窃取或修改的有效手段。

4)数据库定期备份

5)审计追踪机制

审计追踪机制是指系统设置相应的日志记录,特别是对数据更新、删除、修改的记录,以便日后查证。日志记录的内容可以包括操作人员的名称、使用的密码、用户的IP地址、登录时间、操作内容等。若发现系统的数据遭到破坏,可以根据日志记录追究责任,或者从日志记录中判断密码是否被盗,以便修改密码,重新分配权限,确保系统的安全。

Redis
1.Redis 的数据结构都有哪些。
字符串(strings):存储整数(比如计数器)和字符串(废话。。),有些公司也用来存储json/pb等序列化数据,并不推荐,浪费内存

哈希表(hashes):存储配置,对象(比如用户、商品),优点是可以存取部分key,对于经常变化的或者部分key要求atom操作的适合

列表(lists):可以用来存最新用户动态,时间轴,优点是有序,确定是元素可重复,不去重

集合(sets):无序,唯一,对于要求严格唯一性的可以使用

有序集合(sorted sets):集合的有序版,很好用,对于排名之类的复杂场景可以考虑https://redis.readthedocs.io/en/2.4/list.html

2.redis2 和 redis3 的区别,redis3 内部通讯机制。

集群方式的区别,3采用Cluster,2采用客户端分区方案和代理方案

通信过程说明:

1) 集群中的每个节点都会单独开辟一个TCP通道, 用于节点之间彼此 通信, 通信端口号在基础端口上加10000。

2) 每个节点在固定周期内通过特定规则选择几个节点发送ping消息。

3) 接收到ping消息的节点用pong消息作为响应。

3.Redis 的并发竞争问题如何解决,了解 Redis 事务的 CAS 操作吗。
Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法:

1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。

2.服务器角度,利用setnx实现锁。

MULTI,EXEC,DISCARD,WATCH 四个命令是 Redis 事务的四个基础命令。其中:

MULTI,告诉 Redis 服务器开启一个事务。注意,只是开启,而不是执行 EXEC,告诉 Redis 开始执行事务 DISCARD,告诉 Redis 取消事务 WATCH,监视某一个键值对,它的作用是在事务执行之前如果监视的键值被修改,事务会被取消。

可以利用watch实现cas乐观锁

http://wiki.jikexueyuan.com/project/redis/transaction-mechanism.html

http://www.jianshu.com/p/d777eb9f27df

4.redis集群怎么连接
通过client连接时,在命令最后添加-c指令:# redis01/redis-cli -p 7002 -c

-c:代表连接的是redis集群

5.Redis5种数据类型,常用命令
数据类型:String,hash,list,set,sortedset

常用命令:get,set,incr,decr,exists,lpush,lpop,rpush,rpop

6.本网站外部的子网站怎么实现单点登录
对外提供单点登陆的接口,实现验证

共享cookie,cookie是不能跨域访问的,但是在二级域名是可以共享cookie的,所以我们设计将多个系统的一级域名统一的,二级域名不同来区别每个系统,然后token写入cookie时,设置cookie的domain和path属性,这样访问其他子网站时会携带cookie,然后就可以访问cookie中的token,根据token去查询redis中缓存的数据

7.说说你用了redis缓存,你redis存的是什么格式的数据,是怎么存的
存储的都是key-value格式的,比如说session信息,key为“前缀:token”,value为user对象转换的json数据

8.你前台portal采用4台服务器集群部署,那能前台高并发访问性能提上去了,那数据库会不会造成一个瓶颈,这一块你是怎么处理的
portal系统在高并发的情况下如果每次请求都请求查询数据库确实会出现数据库的瓶颈。为了降低数据库压力,在服务层会添加一个缓存,用redis实现,这样的话请求先到缓存中查找是否有缓存的内容,如果有直接从缓存中取数据,如果没有再到数据库中查询。这样数据库的压力就不会那么大了

9.你购物车存cookie里边 可以实现不登录就可以使用购物车 那么我现在没有登录把商品存购物车了 然后登录了 然后我换台电脑并且登录了还能不能看见我购物车的信息?如果看不到怎么做到cookie同步,就是在另外一台电脑上可以看到购物车信息
淘淘商城现阶段使用的仅仅是把购物车的商品写入cookie中,这样服务端基本上么有存储的压力。但是弊端就是用户更换电脑后购物车不能同步。打算下一步这么实现:当用户没有登录时向购物车添加商品是添加到cookie中,当用户登录后购物车的信息是存储在redis中的并且是跟用户id向关联的,此时你更换电脑后使用同一账号登录购物车的信息就会展示出来

10.redis为什么可以做缓存?项目中使用redis的目的是什么?redis什么时候使用?
1)Redis是key-value形式的nosql数据库,可以快速的定位到所查找的key,并把其中的value取出来,并且redis的所有的数据都是放到内存中,存取的速度非常快,一般都是用来做缓存使用。

2)项目中使用redis一般都是作为缓存来使用的,缓存的目的就是为了减轻数据库的压力提高存取的效率。

3)在互联网项目中只要是涉及高并发或者是存在大量读数据的情况下都可以使用redis作为缓存。当然除了缓存还可以根据实际的业务场景来决定redis的作用。例如使用redis保存用户的购物车信息、session信息

11.Redis 的优点?
1.性能极高

– Redis 能支持超过 100K+ 每秒的读写频率。

2.丰富的数据类型

– Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

3.原子

– Redis 的所有操作都是原子性的,同时 Redis 还支持对几个操作全并后的原子性执行。

4.丰富的特性

– Redis 还支持 publish/subscribe, 通知, key 过期等等特性。

12.Redis 的缺点?
是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此 Redis 适合的场景主要 局限在较小数据量的高性能操作和运算上。

13.Redis 集群
集群指的是将几台服务器集中在一起,实现同一业务

  1. 目的:高可用、负载均衡、易扩展、数据安全、性能提升

  2. 技术:集群地址(虚拟 IP)、网络通信(监控消息)

  3. 功能:负载均衡、读写分离、故障转移

14.redis缓存会出现什么问题?
redis缓存数据库的数据,有一点就显得特别重要,那就是数据一致性的问题。

单个数据库在多线程操作的时候如果不是数据库锁的限制会出现很多数据不一致的问题,ACID这里我就不多说了。

redis缓存也会有这样的问题,就是数据库的数据更新到redis是会有时间差的,这样的时间差就会导致数据不一致。

比如一件商品价格在数据库里面是500,然后redis也是500,但是突然数据库修改成了600,如果所有用户都是读入数据库的话,数据库会加锁,然后避免用户读出之前那个500,但是redis的更新怎么说都是有时间差的,所以用户就有可能读取到500这个数据。

这就是数据不一致的问题。

15.redis适合缓存怎么样的数据?
这里的数据分为两块,第一是数据库的数据,第二是页面的一些静态数据。

这里说的是数据库的数据。

页面的一些静态数据不适合存放在缓存中。

然后对于上面提出的数据不一致的问题,所以缓存的数据也有要求。

16.缓存的同步机制,数据更新后怎么办
redis做缓存,先从redis读,读不到进数据库,再存入redis

1、 那比如数据库更新了怎么操作。 数据库和redis各写一遍更新命令执行!

2、 缓存数据设置超时。 超时之后读不到,继续进数据库读,再存入!

dubbo
1.dubbo的作用
提供RPC远程服务调用方案,实现不同系统之间的通信的,解决分布式部署,soa服务治理问题,

Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。

2.Dubbo心跳机制,通信过程
心跳:心跳机制是定时发送一个自定义的结构体([心跳包],让对方知道自己还活着,以确保连接的有效性的机制

心跳机制:

ConfigServer配置中心和每个server/client之间会作一个实时的心跳检测(因为它们建立的是长连接),比如几秒钟检测一次,收集每个server提供的服务信息,每个client信息,整理出一个服务列表

当某个server不可用时,就会更新受影响的服务的服务提供者列表,把这个服务提供者给删除掉,同时将新的服务提供者列表推送给消费者

当某个消费者挂了,就会更新受影响的服务对应的消费者列表

通信过程:

服务容器启动时,加载运行服务提供者

服务提供者启动时,向注册中心注册自己提供的服务

服务消费者启动时,向注册中心订阅自己所需的服务

注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者

服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用(当有多个服务提供者的时候,Client根据一定的规则来进行负载均衡,如轮询,随机,按权重等)

服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

3.dubbo服务开发流程,运行流程?zookeeper注册中心的作用?
使用流程:

第一步:要在系统中使用dubbo应该先搭建一个注册中心,一般推荐使用zookeeper。

第二步:有了注册中心然后是发布服务,发布服务需要使用spring容器和dubbo标签来发布服务。并且发布服务时需要指定注册中心的位置。

第三步:服务发布之后就是调用服务。一般调用服务也是使用spring容器和dubbo标签来引用服务,这样就可以在客户端的容器中生成一个服务的代理对象,在action或者Controller中直接调用service的方法即可。

Zookeeper注册中心的作用主要就是注册和发现服务的作用。类似于房产中介的作用,在系统中并不参与服务的调用及数据的传输。

4.Webservice
Webservice就是web应用程序,它能使得运行在不同服务器上的不同应用无须借助其他的软件或硬件,就可相互交换数据或集成,无论这些应用所使用的语言、 平台或内部协议是什么, 都可以相互交换数据;简单说就是进行分布部署的多个系统之间的数据通信

SOAP:(Simple Object Access Protocol)简单对象存取协议。是XML Web Service 的通信协议。SOAP是XML文档形式的调用方法的规范,它可以支持不同的底层接口,像HTTP(S)或者SMTP。

WSDL:(Web Services Description Language) WSDL 文件是一个 XML 文档,用于说明一组 SOAP 消息以及如何交换这些消息。

UDDI (Universal Description, Discovery, and Integration): 是一个主要针对Web服务供应商和使用者的新项目,服务注册中心

数据库相关问题

  1. 什么是存储过程?它有什么优点?
    答:存储过程是一组予编译的SQL语句,它的优点有:

    允许模块化程序设计,就是说只需要创建一次过程,以后在程序中就可以调用该过程任意次。

    允许更快执行,如果某操作需要执行大量SQL语句或重复执行,存储过程比SQL语句执行的要快。

    减少网络流量,例如一个需要数百行的SQL代码的操作有一条执行语句完成,不需要在网络中发送数百行代码。

    更好的安全机制,对于没有权限执行存储过程的用户,也可授权他们执行存储过程。

  2. oracle的存储过程和函数有什么区别?
    Oracle中的函数与存储过程的区别:

    A:函数必须有返回值,而过程没有.

    B:函数可以单独执行.而过程必须通过execute执行.

    C:函数可以嵌入到SQL语句中执行.而过程不行.

    其实我们可以将比较复杂的查询写成函数.然后到存储过程中去调用这些函数.

Oracle中的函数与存储过程的特点:

A. 一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。 

B. 对于存储过程来说可以返回参数,而函数只能返回值或者表对象。     

C.存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。
  1. 什么是事务?
    答:事务是指一个工作单元,它包含了一组数据操作命令,并且所有的命令作为一个整体一起向系统提交或撤消请求操作,即这组命令要么都执行,要么都不执行。

    原子性:事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。

    一致性:事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。

    隔离性:由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。

    持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。

  2. 什么是索引?它有什么优点?
    答:索引象书的目录类似,索引使数据库程序无需扫描整个表,就可以在其中找到所需要的数据,索引包含了一个表中包含值的列表,其中包含了各个值的行所存储的位置,索引可以是单个或一组列,索引提供的表中数据的逻辑位置,合理划分索引能够大大提高数据库性能。

  3. 什么是触发器,它有哪些优点?说说你遇到过的常见应用?
    答:触发器是一种特殊类型的存储过程,触发器主要通过事件触发而被执行的,触发器的优点:

①.强化约束,触发器能够提供比CHECK约束。

②.跟踪变化,触发器可以跟踪数据库内的操作,从而不允许未经允许许可的更新和变化。

③.联级运算,比如某个表上的触发器中包含对另一个表的数据操作,而该操作又导致该表上的触发器被触发。

  1. 触发器分为事前触发和事后触发的区别。语句级触发和行级触发有何区别?
    事前触发器运行于触发事件发生之前,通常可以获取事件之前和新的字段值

事后触发器运行于触发事件发生之后。

语句级触发器可以在语句执行前或后执行,

行级触发在触发器所影响的每一行触发一次

  1. 视图是什么?游标是什么?
    答:视图是一种虚拟表,虚拟表具有和物理表相同的功能,可以对虚拟表进行增该查操作,视图通常是一个或多个表的行或列的子集,视图的结果更容易理解(修改视图对基表不影响),获取数据更容易(相比多表查询更方便),限制数据检索(比如需要隐藏某些行或列),维护更方便。

游标对查询出来的结果集作为一个单元来有效的处理,游标可以定位在结果集的特定行、从结果集的当前位置检索一行或多行、可以对结果集中当前位置进行修改。

  1. 怎么优化数据库(在数据百万条记录的数据库中 Oracle)?
    使用索引

建立分区,分区索引

使用存储过程

  1. 如何优化SQL语句
    ①. 对操作符的优化 尽量不采用不利用索引的操作符
    如:in ,not in , is nul, is not null,<>等
    ②. 对条件字段的一些优化
    采用函数处理的字段不能利用索引,
    进行了显式或隐式的运算的字段不能进行索引

    条件内包括了多个本表的字段运算时不能进行索引

    ③. 在业务密集的SQL当中WHERE后面的条件顺序影响

    ④. 应用ORACLE的HINT(提示)处理
    ⑤. 查询表顺序的影响

  2. 使用索引查询一定能提高查询的性能吗?为什么?
    不能。如果返回的行数目较大,使用全表扫描的性能较好。

  3. 操作符优化
    ①.IN 操作符
    用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格。但是用IN的SQL性能总是比较低的,从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有以下区别:

ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。

推荐方案:在业务密集的SQL当中尽量不采用IN操作符,用EXISTS 方案代替。

②.NOT IN操作符
此操作是强列不推荐使用的,因为它不能应用表的索引。

推荐方案:用NOT EXISTS 方案代替

③.IS NULL 或IS NOT NULL操作(判断字段是否为空)
判断字段是否为空一般是不会应用索引的,因为索引是不索引空值的。

推荐方案:用其它相同功能的操作运算代替,如:a is not null 改为 a>0 或a>’’等。不允许字段为空,而用一个缺省值代替空值,如申请中状态字段不允许为空,缺省为申请。

④.> 及 < 操作符(大于或小于操作符)
大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有100万记录,一个数值型字段A,30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为A>2时ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到=3的记录索引。

⑤.LIKE操作符
LIKE操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。

一个实际例子:用YW_YHJBQK表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 则会利用YY_BH的索引进行两个范围的查询,性能肯定大大提高。

⑥.UNION操作符
UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

推荐方案:采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。

select * from gc_dfys
union all
select * from ls_jg_dfys

  1. 说说你知道的一些关于查询优化的方案?
    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。

3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,

5.in 和 not in 也要慎用,否则会导致全表扫描。

6.下面的查询也将导致全表扫描

7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。

8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。

9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。

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

11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

12.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

13.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

14.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

16.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

SQL语句的优化(简洁):

<一> :尽量使用单表查询,不适用多表查询(子查询)

<二> :使用distinct

<三> :尽量使用较小的列

<四> :频繁使用的字段加索引

<五> :避免使用select* 和 like 查询

<六> :数据量在百万级以上,使用分表查询,时时分割表

<七> :避免在索引列上使用计算,not ,in 等操作

<八> :当只需要一行数据的时候,使用limit

<九> :针对查询较慢的语句,可以使用explain来分析该语句具体的执行情况

  1. 谈谈你对SQL海量数据查询优化性能的一些看法?
    数据库系统是管理信息系统的核心,基于数据库的联机事务处理(OLTP)以及联机分析处理(OLAP)是银行、企业、政府等部门最为重要的计算机应用之一。从大多数系统的应用实例来看,查询操作在各种数据库操作中所占据的比重最大,而查询操作所基于的SELECT语句在SQL语句中又是代价最大的语句。举例来说,如果数据的量积累到一定的程度,比如一个银行的账户数据库表信息积累到上百万甚至上千万条记录,全表扫描一次往往需要数十分钟,甚至数小时。如果采用比全表扫描更好的查询策略,往往可以使查询时间降为几分钟,由此可见查询优化技术的重要性。

百万数据查询优化技巧三十则见问题12

  1. 数据库内联与外联的区别?
    内部联接(inner join)一个联接,返回两表的公共列都匹配的行

外部联接(outer join) 一个联接,该联接还包括那些和联接表中记录不相关的记录。您可以创建一个外部联接的三种变形来指定所包括的不匹配行:

左外部联接、右外部联接和完全外部联接。

u 左外部联接(left outer join) 左边的表是主表,列所有;右表无取null

u 右外部联接(right outer join) 右边的表是主表,列所有;左边表只列匹配的行,没有值置null

u 完全外部联接 列所有,没有值置null

  1. 数据库中,我们对主键有哪些要求?
    非空、唯一、可引用!

  2. 分别说说MySQL和oracle的分页?
    oracle使用rownum加上嵌套子查询完成分页功能

SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21

MySQL使用的是limit函数

SELECT * FROM table LIMIT 5,10; //查询的是第6条到第15条数据,注意,10位偏移量。

19.数据库会死锁吗,举一个死锁的例子,mysql 怎么解决死锁。
产生死锁的原因主要是:

(1)系统资源不足。

(2) 进程运行推进的顺序不合适。

(3)资源分配不当等。

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。

(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

这里提供两个解决数据库死锁的方法:

1)重启数据库

2)杀掉抢资源的进程:

先查哪些进程在抢资源:SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

杀掉它们:Kill trx_mysql_thread_id;

Nginx
1.简述Nginx集群和作用
将同一个业务部署在多台机器上,提高系统的高可用性

2.niginx负载均衡有哪几种方式
轮询(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

Weight(权重)

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

ip_hash

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。

fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效

3.简述Nginx 与 Apache的区别
1.1、nginx相对于apache的优点:
轻量级,同样起web 服务,比apache占用更少的内存及资源抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能高度模块化的设计,编写模块相对简单社区活跃,各种高性能模块出品迅速啊
apache 相对于nginx 的优点:
rewrite ,比nginx 的rewrite 强大,动态页面,模块超多,基本想到的都可以找到,少bug ,nginx 的bug 相对较多,超稳定
存在就是理由,一般来说,需要性能的web 服务,用nginx 。如果不需要性能只求稳定,那就apache 吧。后者的各种功能模块实现得比前者,例如ssl 的模块就比前者好,可配置项多。这里要注意一点,epoll(freebsd 上是 kqueue )网络IO 模型是nginx 处理性能高的根本理由,但并不是所有的情况下都是epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache 的select 模型或许比epoll 更高性能。
1.2、作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应, 感谢Nginx为我们选择了 epoll and kqueue 作为开发模型.
Nginx作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行服务. Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多.
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last.fm 描述了成功并且美妙的使用经验.
Nginx 是一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够不间断服务的情况下进行软件版本的升级 .
1.3 nginx处理静态文件好,耗费内存少.但无疑apache仍然是目前的主流,有很多丰富的特性.所以还需要搭配着来.当然如果能确定nginx就适合需求,那么使用nginx会是更经济的方式.
apache有先天不支持多核心處理負載雞肋的缺點,建議使用nginx做前端,後端用apache。大型網站建議用nginx自代的集群功能

1.4 nginx处理动态请求是鸡肋,一般动态请求要apache去做,nginx只适合静态和反向。

4.Nginx反向代理为什么可以提高网站性能?
对于后端是动态服务来说,比如Java和PHP。这类服务器(如JBoss和PHP-FPM)的IO处理能力往往不高。

Nginx有个好处是它会把Request在读取完整之前buffer住,这样交给后端的就是一个完整的HTTP请求,从而提高后端的效率,而不是断断续续的传递(互联网上连接速度一般比较慢)。

同样,Nginx也可以把response给buffer住,同样也是减轻后端的压力。

5.Httpclient是什么
HttpClient不是一个浏览器。它是一个客户端的HTTP通信实现库。HttpClient的目标是发送和接收HTTP报文。HttpClient不会去缓存内容,执行嵌入在HTML页面中的javascript代码,猜测内容类型,重新格式化请求/重定向URI,或者其它和HTTP运输无关的功能.它主要就是支持HTTP传输协议的.

6.jsonp是什么?
JSONP 的原理非常简单,为了克服跨域问题,利用没有跨域限制的 script 标签加载预设的 callback 将内容传递给 js。一般来说我们约定通过一个参数来告诉服务器 JSONP 返回时应该调用的回调函数名,然后拼接出对应的 js。

基础
1.Java 中会存在内存泄漏吗,请简单描述。
答:理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

2.阐述静态变量和实例变量的区别。
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

补充:在Java开发中,上下文类和工具类中通常会有大量的静态成员。

3.如何实现对象克隆?
答:有两种方式:

1). 实现Cloneable接口并重写Object类中的clone()方法;

2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

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

垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。

5.String s = new String(“xyz”);创建了几个字符串对象?
答:两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。

6.数据类型之间的转换:

  • 如何将字符串转换为基本数据类型?

  • 如何将基本数据类型转换为字符串?

答:

  • 调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;

  • 一种方法是将基本数据类型与空字符串("")连接(+)即可获得其所对应的字符串;另一种方法是调用String 类

中的valueOf()方法返回相应字符串

7.try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?
答:会执行,在方法返回调用者前执行。

注意:在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值。显然,在finally中返回或者修改返回值会对程序造成很大的困扰,C#中直接用编译错误的方式来阻止程序员干这种龌龊的事情,Java中也可以通过提升编译器的语法检查级别来产生警告或错误,Eclipse中可以在如图所示的地方进行设置,强烈建议将此项设置为编译错误。

8.Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答:Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法可能抛出的各种异常(当然声明异常时允许无病呻吟);finally为确保一段代码不管发生什么异常状况都要被执行;try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM。

9.阐述ArrayList、Vector、LinkedList的存储性能和特性。
答:ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector中的方法由于添加了synchronized修饰,因此Vector是线程安全的容器,但性能上较ArrayList差,因此已经是Java中的遗留容器。LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。Vector属于遗留容器(Java早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),已经不推荐使用,但是由于ArrayList和LinkedListed都是非线程安全的,如果遇到多个线程操作同一个容器的场景,则可以通过工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用(这是对装潢模式的应用,将已有对象传入另一个类的构造器中创建新的对象来增强实现)。

10List、Map、Set三个接口存取元素时,各有什么特点?
答:List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。Set和Map容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。

11Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?
答:sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

12线程的sleep()方法和yield()方法有什么区别?
答:

① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;

③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;

④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

13编写多线程程序有几种实现方式?
答:Java 5以前实现多线程有两种实现方法:一种是继承Thread类;另一种是实现Runnable接口。两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活。

补充:Java 5以后创建线程还有第三种方式:实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值.

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

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

16.如何通过反射创建对象?
答:

  • 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()

  • 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);

17.如何通过反射获取和设置对象私有字段的值?
答:可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。下面的代码实现了一个反射的工具类,其中的两个静态方法分别用于获取和设置私有字段的值,字段可以是基本类型也可以是对象类型且支持多级对象操作。

18.简述一下你了解的设计模式。
答:所谓设计模式,就是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。

  • 工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,

但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。

  • 代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。

  • 适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。

  • 模板方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。除此之外,还可以讲讲上面提到的门面模式、桥梁模式、单例模式、装潢模式(Collections工具类和I/O系统中都使用装潢模式)等。

19.转发(forward)和重定向(redirect)的区别?
答:forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL 的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址,很明显redirect无法访问到服务器保护起来资源,但是可以从一个网站redirect到其他网站。forward更加高效,所以在满足需要时尽量使用forward(通过调用RequestDispatcher对象的forward()方法,该对象可以通过ServletRequest对象的getRequestDispatcher()方法获得),并且这样也有助于隐藏实际的链接;在有些情况下,比如需要访问一个其它服务器上的资源,则必须使用重定向(通过

HttpServletResponse对象调用其sendRedirect()方法实现)。

20.get和post请求的区别?
答:

①get请求用来从服务器上获得资源,而post是用来向服务器提交数据;

②get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用"?“连接,而各个变量之间使用”&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL;

③get传输的数据要受到URL长度限制(1024字节);而post可以传输大量的数据,上传文件通常要使用post方式;

④使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post;

⑤get使用MIME类型application/x-www-form-urlencoded的URL编码(也叫百分号编码)文本的格式传递参数,保证被传送的参数由遵循规范的文本组成,例如一个空格的编码是"%20"。

21.JSP和Servlet是什么关系?
答:其实这个问题在上面已经阐述过了,Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。有人说,Servlet就是在Java中写HTML,而JSP就是在HTML中写Java代码,当然这个说法是很片面且不够准确的。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)。

22.如何实现JSP或Servlet的单线程模式?
答:

对于JSP页面,可以通过page指令进行设置。

<%@page isThreadSafe=”false”%>

对于Servlet,可以让自定义的Servlet实现SingleThreadModel标识接口。

说明:如果将JSP或Servlet设置成单线程工作模式,会导致每个请求创建一个Servlet实例,这种实践将导致严重的性能问题(服务器的内存压力很大,还会导致频繁的垃圾回收),所以通常情况下并不会这么做。

集合
1.ArrayList 和 LinkedList 有什么区别。
ArrayList和LinkedList都实现了List接口,有以下的不同点:

a、ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。所以ArrayList的查询是要比LinkedList要快。

b、相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。

c、LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。

2.ArrayList 底层实现方式?
a、ArrayList 底层是通过数组实现,一旦实例化 ArrayList 无参构造函数,那么默认数组初始化长度就为 10。

b、add 方法底层实现如果增加的元素个数超过了 10 个,那么 ArrayList 底层会新生成一个数组,长度为原数组的 1.5 倍+1(jdk1.6之前,1.7以后是用的位运算(效率更高),是1.5倍),然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组当中。当新数组无法容纳增加的元素时,重复该过程。是一旦数组超出长度,就开始扩容数组。扩容数组调用的方法 Arrays.copyOf(objArr, objArr.length + 1);

3.LinkedList 底层实现方式?
a、LinkedList 底层的数据结构是基于双向循环链表的,且头结点中不存放数据。

b、LinkedList包含两个重要的成员:header 和 size。
   header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。
   size是双向链表中节点的个数。

c、从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
d、LinkedList底层的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。

4.HashSet的底层实现方式?
a、HashSet底层实现是一个HashMap用来保存数据,实现Set接口。

b、线程不安全,存取速度快。

c、默认初始容量为16,加载因子为0.75:即当元素个数超过容量长度的0.75倍时,进行扩容,扩容大小为原容量的2倍。如HashSet的容量为16,一次扩容后是容量为32

5.HashMap的底层实现之扩容?
HashMap的默认初始容量为16(为何是16:16是2^4,可以提高查询效率,另外,32=16<<1)加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容,扩容后大小为原容量的2倍。

6.Hashtable的底层实现之扩容?
Hashtable 是线程安全的,底层方法都用Sychronized修饰的。默认初始容量为11,加载因子为0.75:即当元素个数超过容量长度的0.75倍 时,进行扩容,扩容后的大小为原容量的2倍+1,如 Hashtable的容量为11,一次扩容后是容量为23

7.ArrayList 集合加入11万条数据,应该怎么提高效率?
因为 ArrayList 的底层是数组实现,并且数组的默认值是 10,如果插入10000 条要不断的扩容,耗费时间,所以我们调用 ArrayList 的指定容量的构造器方法 ArrayList(int size) 就可以实现不扩容,就提高了性能。

8.以下是关于HashMap 面试题
HashMap 的工作原理是近年来常见的 Java 面试题。几乎每个 Java 程序员都知道 HashMap,都知道哪里要用 HashMap,知道 Hashtable 和 HashMap 之间的区别,那么为何这道面试题如此特殊呢?是因为这道题考察的深度很深。这题经常出现在高级或中高级面试中。投资银行更喜欢问这个问题,甚至会要求你实现 HashMap 来考察你的编程能力。ConcurrentHashMap 和其它同步集合的引入让这道题变得更加复杂。让我们开始探索的旅程吧!先来些简单的问题

8.1你用过 HashMap 吗?什么是 HashMap?你为什么用到它?
几乎每个人都会回答“是的”,然后回答 HashMap 的一些特性,譬如 HashMap可以接受 null 键值和值,而 Hashtable 则不能;HashMap 是非synchronized;HashMap 很快;以及 HashMap 储存的是键值对等等。这显示出你已经用过 HashMap,而且对它相当的熟悉。但是面试官来个急转直下,从此刻开始问出一些刁钻的问题,关于 HashMap 的更多基础的细节。面试官可能会问出下面的问题:

8.2你知道 HashMap的工作原理吗? 你知道 HashMap 的get()方法的工作原理吗?
你也许会回答“我没有详查标准的 Java API,你可以看看 Java 源代码或者Open JDK。”“我可以用 Google 找到答案。”但一些面试者可能可以给出答案,“HashMap 是基于 hashing 的原理,我们使用 put(key, value)存储对象到 HashMap 中,使用 get(key)从 HashMap 中获取对象。当我们给 put()方法传递键和值时,我们先对键调用 hashCode()方法,返回的 hashCode 用于找到 bucket 位置来储存 Entry 对象。”这里关键点在于指出,HashMap 是在 bucket 中储存键对象和值对象,作为 Map.Entry。这一点有助于理解获取对象的逻辑。如果你没有意识到这一点,或者错误的认为仅仅只在 bucket 中存储值的话,你将不会回答如何从 HashMap 中获取对象的逻辑。这个答案相当的正确,也显示出面试者确实知道 hashing 以及 HashMap 的工作原理。但是这仅仅是故事的开始,当面试官加入一些 Java 程序员每天要碰到的实际场景的时候,错误的答案频现。下个问题可能是关于 HashMap 中的碰撞探测(collision detection)以及碰撞的解决方法:

8.3当两个对象的 hashcode 相同会发生什么?
从这里开始,真正的困惑开始了,一些面试者会回答因为 hashcode 相同,所以两个对象是相等的,HashMap 将会抛出异常,或者不会存储它们。然后面试官可能会提醒他们有 equals()和 hashCode()两个方法,并告诉他们两个对象就算hashcode 相同,但是它们可能并不相等。一些面试者可能就此放弃,而另外一些还能继续挺进,他们回答“因为 hashcode 相同,所以它们的 bucket 位置相同,‘碰撞’会发生。因为 HashMap 使用链表存储对象,这个 Entry(包含有键值对的 Map.Entry 对象)会存储在链表中。”这个答案非常的合理,虽然有很多种处理碰撞的方法,这种方法是最简单的,也正是 HashMap 的处理方法。但故事还没有完结,面试官会继续问:

8.4如果 HashMap 的大小超过了负载因子(load factor)定义的容量,怎么办?
默认的负载因子大小为 0.75,也就是说,当一个 map 填满了 75%的 bucket 时候,和其它集合类(如 ArrayList 等)一样,将会创建原来 HashMap 大小的两倍的 bucket 数组,来重新调整 map 的大小,并将原来的对象放入新的 bucket 数组中。这个过程叫作 rehashing,因为它调用 hash 方法找到新的 bucket 位置。如果你能够回答这道问题,下面的问题来了:

8.5 HashMap 的工作原理
HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。

HashMap 底层采用一个Entry[] 数组来保存所有的key-value 对,当需要存储一个Entry 对象时,会根据 hash 算法来决定其在数组中的存储位置,在据equals 方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

8.6 HashMap和Hashtable 的区别
HashMap 和 Hashtable 都实现了 Map 接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

HashMap 几乎可以等价于 Hashtable,除了 HashMap 是非 synchronized 的,并可以接null(HashMap 可以接受为 null 的键值(key)和值(value),而 Hashtable 则不行)。

HashMap 是非 synchronized,而 Hashtable 是 synchronized,这意味着 Hashtable 是线程安全的,多个线程可以共享一个 Hashtable;而如果没有正确的同步的话,多个线程是不能共享 HashMap 的。

Java 5 提供了 ConcurrentHashMap,它是 HashTable 的替代,比 HashTable 的扩展性更好。

另一个区别是 HashMap 的迭代器(Iterator)是 fail-fast 迭代器,而 Hashtable 的 enumerator迭代器不是 fail-fast 的。所以当有其它线程改变了 HashMap 的结构(增加或者移除元素),将会抛出

ConcurrentModificationException,但迭代器本身的 remove()方法移除元素则不会抛出 ConcurrentModificationException 异常。但这并不是一个一定发生的行为,要看 JVM。这条同样也是 Enumeration 和 Iterator 的区别。

由于 Hashtable 是线程安全的也是 synchronized,所以在单线程环境下它比 HashMap 要慢。如果你不需要同步,只需要单一线程,那么使用 HashMap 性能要好过 Hashtable。

HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。

8.7 HashSet和HashMap 的区别
HashMap实现了Map 接口HashSet 实现了Set 接口

HashMap 储存键值对 HashSet 仅仅存储对象

使用 put()方法将元素放入 map 中 使用 add()方法将元素放入 set 中

HashMap 中使用键对象来计算 hashcode 值 HashSet 使用成员对象来计算 hashcode 值,对于两个对象来说 hashcode 可能相同,所以 equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回 false

HashMap 比较快,因为是使用唯一的键来获取对象 HashSet 较 HashMap 来说比较慢

Logo

开源、云原生的融合云平台

更多推荐