本帖最后由 yuchengmin 于 2018-9-13 10:59 编辑
Java常见面试题目考点(五)
1、分库分表带来的问题? ① 事务一致性问题: 当更新内容同时分布在不同库中,不可避免会带来跨库事务问题。 解决方案: 分布式事务能最大限度保证了数据库操作的原子性。事务补偿的方式,可以基于日志进行对比,定期同标准数据来源进行同步 ② 跨节点关联查询 join 问题: 全局表, 可以将这类表在每个数据库中都保存一份; 数据组装,分几次查询,再根据id将得到的数据进行拼接; ER分片, 将那些存在关联关系的表记录存放在同一个分片上。 全局主键避重问题: UUID是主键是最简单的方案,本地生成,性能高。 支持分库分表中间件:Vitess(谷歌),mycat(基于cobar)。
2、什么是乐观锁,什么是悲观锁,两者的区别是什么? 悲观锁(Pessimistic Lock): 每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 block 直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁,比如 Java里面的同步原语synchronized关键字的实现也是悲观锁。 在整个数据处理过程中,将数据处于锁定状态。 悲观锁机制存在以下问题: 1. 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题; 2. 一个线程持有锁会导致其它所有需要此锁的线程挂起; 3. 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。
乐观锁(冲突检测和数据更新): 每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,如果因为并发冲突失败就重试,直到成功为止。 CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。 CAS缺点: (1)ABA问题:比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。尽管线程one的CAS操作成功,但可能存在潜藏的问题。如下所示: 现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道A.next为B,然后希望用CAS将栈顶替换为B: head.compareAndSet(A,B);在T1执行上面这条指令之前,线程T2介入,将A、B出栈,再pushD、C、A,此时堆栈结构如下图,而对象B此时处于游离状态: 此时轮到线程T1执行CAS操作,检测发现栈顶仍为A,所以CAS成功,栈顶变为B,但实际上B.next为null,所以此时的情况变为: 其中堆栈中只有B一个元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。 (2)循环时间长开销大:不成功,就一直循环执行,直到成功)如果长时间不成功,会给CPU带来非常大的执行开销; (3)只能保证一个共享栈区变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者就是把多个共享变量合并成一个共享变量来操作。
3、Mybatis框架(优点是什么?缺点是什么?以及在企业开发中有什么好处?你在开发中是怎么使用的?有那些属性)一、MyBatis框架的优点: ① 与JDBC相比,减少了50%以上的代码量; ② MyBatis是最简单的持久化框架,小巧并且简单易学; ③ MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用; ④ 提供XML标签,支持编写动态SQL语句; ⑤ 提供映射标签,支持对象与数据库的ORM字段关系映射。 二、缺点: ① SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求; ② SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库; MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案,对性能的要求很高,或者需求变化较多的项目,如互联网项目,那么MyBatis将是不错的选择。 三、属性: id="selectUser" //与 PersonMapper.java 接口对应的方法 parameterType="int" //传入的参数格式 resultType="hashmap" //返回的数据类型,当返回多个参数的时候,建议使用 resultMap resultMap="userResultMap" //返回的数据类型,相当于对 resultType="hashmap" 的封装。resultType、resultMap两者只能存在一个 flushCache="false" //是否清空缓存,默认为false useCache="true" //是否二级缓存,默认值:对 select 元素为 true。 timeout="10000" //等待数据库返回请求结果的秒数。
4、Springboot的常用注解? @SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文; @Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全; @EnableAutoConfiguration 自动配置; @ComponentScan 组件扫描,可自动发现和装配一些Bean; @Component可配合CommandLineRunner使用,在程序启动后执行一些基础任务; @RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器; @Autowired自动导入; @PathVariable获取参数; @JsonBackReference解决嵌套外链问题; @RepositoryRestResourcepublic配合spring-boot-starter-data-rest使用。
5、rabbitMQ在项目中的应用场景? 主要是完成系统之间的通信,并且将系统之间的调用进行解耦,例如在添加商品信息后,需要将商品信息同步到索引库,同步缓存中的数据,一旦后台对商品信息进行修改后,就像activeMQ发送一条消息,然后通过activeMQ将消息发送给消息的消费端,消费端接收到消息后可以进行相应的业务处理。 5.1、rabbitMQ的5种消息模型? ① 基本消息模型:
- P:生产者,也就是要发送消息的程序 C:消费者:消息的接受者,会一直等待消息到来。 - queue:消息队列,图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。 ② work消息模型: 让多个消费者绑定到一个队列,共同消费队列中的消息。队列中的消息一旦消费,就会消失,因此任务是不会被重复执行的。 ③ 订阅模型-Fanout(广播):
: - 1) 可以有多个消费者 - 2) 每个消费者有自己的queue(队列) - 3) 每个队列都要绑定到Exchange(交换机) - 4) 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。 - 5) 交换机把消息发送给绑定过的所有队列 - 6) 队列的消费者都能拿到消息。实现一条消息被多个消费者消费 ④ 订阅模型-Direct:
: - 队列与交换机的绑定,不能是任意绑定了,而是要指定至少一个RoutingKey(路由key) - 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey。 - Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息。 ⑤ 订阅模型-Topic: Topic类型的Exchange与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符! 通配符规则:#:匹配一个或多个词*:匹配不多不少恰好1个词 5.2、rabbitMQ如果数据提交不成功怎么办? rabbitMQ有两种通信方式:点到点形式和发布订阅模式,点到点模式的话,如果消息发送不成功,消息会默认保存到服务端直到有消费者将其消费掉,所以此时消息是不会丢失的.发布订阅模式的通信方式,此时就需要将配置持久化(队列持久化,交换机持久化,消息持久化),发送消息和接收消息需要配置发送模式为持久化,此时如果客户端接收不到消息,消息就会持久化到服务端,直到客户端正常接收为止。 5.3、rabbitMQ的常见问题? ① RabbitMQ队列超长导致QueueingConsumerJVM溢出; ② RabbitMQ数据速率问题, 在边读边写的情况下:速率只与网络带宽正相关; 在只写不读的情况下:写入速率瓶颈在于硬盘写入速度; ③ RabbitMQ数据存储路径变更到D盘方法: Windows环境下,在安装前设置环境变量:RABBITMQ_BASE=D:\RabbitMQ_Data; ④ RabbitMQ磁盘写满重启后数据丢失问题。 5.4 rabbtiMQ消息阻塞. ① 消息会处于阻塞状态: 解决阻塞的办法,可以在subscribe消息队列是设置autoAck=true,这种情况是worker接到消息后,就会把消息从消息队列删除,不管消息是否被正确处理,另一种是设置autoAck=false,这样worker在接受消息后,必须给予服务端一个ack响应,该消息才会从消息队列中删除,这样会防止消息的意外丢失; ② 关于健壮的消息处理: 当rabbitmq server重启,或意外当掉的话,所用消息的订阅都会跟着坏掉(当然也可以设置持久化的消息队列设置),解决办法是捕获ShutdownSignalException异常。
6、页面静态化? ① 使用freemarker实现生成静态页面,将页面的实际存在于服务器的硬盘中,然后通过nginx反向代理服务器访问资源; ② WEB服务器的 URL Rewrite的方式, 一句话来说就是把外部请求的静态地址转化为实际的动态页面地址,静态页面实际是不存在的。
7、谈谈你对elasticsearch的理解? 是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎 - 分布式,无需人工搭建集群(solr就需要人为配置,使用Zookeeper作为注册中心); - Restful风格,一切API都遵循Rest原则,容易上手; - 近实时搜索,数据更新在Elasticsearch中几乎是完全同步的。
8、谈谈你对node.js的理解?概念: 1. Node.js是一个基于Chrome V8引擎的javascipt的运行环境; 2. Node.js使用了一个事件驱动、非阻塞I/O的模型; 3. Node.js轻量又高效,能够使我们在本地运行javascript。 作用: 1、提供数据给浏览器展示 2、保存用户提交过来的数据 3、数据统计与分析
9、谈谈对springcloud的理解? SpringCloud是Spring为微服务架构思想做的一个一站式实现。提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。最重要的是,跟SpringBoot框架一起使用的话,会让你开发微服务架构的云服务非常方便。组件有: - Eureka:注册中心 - Zuul:服务网关 - Ribbon:负载均衡 - Feign:服务调用(集成了负载) - Hystix:熔断器 - Feign:服务调用 - springCloud config它支持配置文件放在在配置服务的内存中,也支持放在远程Git仓库里。
10、eureka的理解?- Eureka:就是服务注册中心(可以是一个集群),对外暴露自己的地址 - 提供者:启动后向Eureka注册自己信息(地址,提供什么服务) - 消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新 - 心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态
11.JWT的理解? JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权。 - 1、用户登录 - 2、服务的认证,通过后根据secret生成token - 3、将生成的token返回给用户 - 4、用户每次请求携带token - 5、服务端解读jwt签名,判断签名有效后,从Payload中获取用户信息 - 6、处理请求,返回响应结果
12、REST风格的WEB设计原则 ① 使用客户/服务器模型。客户和服务器之间通过一个统一的接口来互相通讯。 ② 层次化的系统. 在一个REST系统中,客户端并不会固定地与一个服务器打交道。 ③ 无状态,在一个REST系统中,服务端并不会保存有关客户的任何状态。也就是说,客户端自身负责用户状态的维持,并在每次发送请求时都需要提供足够的信息。 ④ 可缓存,REST系统需要能够恰当地缓存请求,以尽量减少服务端和客户端之间的信息传输,以提高性能。 ⑤ 统一的接口,一个REST系统需要使用一个统一的接口来完成子系统之间以及服务与用户之间的交互。这使得REST系统中的各个子系统可以独自完成演化。
|