javaEE工程师面试题(高级部分)

java工程师,你需要知道的还有很多!如今的Web工程师,不仅要懂java基础,框架,servlet,前端,还要会各种框架整合,什么ssh,ssm.....诸如此类吧。不可否认,这些是根基,但要作为一个高级工程师,面试必然会问到的还包括如下一些,大家好好准备下。

先来个框架的

1.mybatis是如何将结果集映射为对象的?

首先,mybatis是对jdbc的封装,再怎么样也是查出结果集然后用一个ResultSetHandler将结果集映射为我们定义的比如User这样的对象,但属性和列名如何对应呢?

大家应该都记得吧,有两种:

Mybatis的输出映射,也就是对查询结果集的一个映射,主要有两种:

    1.resultType(不需要配置,可以直接用),这种方式必须保证列名和属性名完全一样才能自动配上,要么写得SQL就要用as起别名

      一般是实体类

      基本类型也可以

    2.resultMap(需要配置resultMap与之对应)

扫描二维码关注公众号,回复: 4245183 查看本文章
     还记得咋写吗?这样:


  
  
  1. <resultMap type="student" id="studentResultMap">
  2. <!--
  3. id:查询结果的唯一标识
  4. 不是id结果的映射
  5. column:查询出来的列名
  6. property:type指定的实体类的属性名
  7. -->
  8. <id column="sid_" property="sid"/>
  9. <result column="name_" property="name"/>
  10. <result column="sex_" property="sex"/>
  11. <result column="hobbies_" property="hobbies"/>
  12. </resultMap>


2.来看第二题,mybatis有几种executor?

这个问题问到了mybatis源码层面了,有一定难度,但是答案比较简单。平时我们使用dao接口,mybatis会为我们生成代理类,一般都是这么做。但是别忘了一开始我们用的是sqLSession进行的增删改查。

SQLSession类,比如我们用到selectList(配置文件select标签id),这个在源码中是这样的:


  
  
  1. public <E> List <E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  2. 2 try {
  3. 3 MappedStatement ms = configuration.getMappedStatement(statement);
  4. 4 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  5. 5 } catch (Exception e) {
  6. 6 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
  7. 7 } finally {
  8. 8 ErrorContext.instance().reset();
  9. 9 }
  10. 10 }
第三行是获取具体sql,注意第四行executor出现了,其实这是mybatis执行sql的接口,看名字就知道是执行sql的意思。他有三个子类:

ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
ExecutorType.BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是 必须的,来保证一个简单并易于理解的行为。
默认用的是simple执行器。这就是本题的答案。

3.第三题,依旧mybatis, 如何批处理?

我们平时做项目都是执行一句sql,配置在xml文件中。但是如果批量插入100条数据咋办?配置100个insert标签,不是的。

给大家提供两种方式批处理:1、mapper文件中使用foreach标签拼装语句,比如批量插入好多条,形如:


  
  
  1. <insert id="insertbatch" parameterType="java.util.List">
  2. <selectKey keyProperty="fetchTime" order="BEFORE"
  3. resultType= "java.lang.String">
  4. SELECT CURRENT_TIMESTAMP()
  5. </selectKey>
  6. insert into kangaiduoyaodian ( depart1, depart2, product_name) values
  7. <foreach collection="list" item="item" index="index"
  8. separator= ",">
  9. ( #{item.depart1}, #{item.depart2}, #{item.productName} )
  10. </foreach>
  11. </insert>
上面的collection属性的list是传过来的参数集合。

同样道理,批量更新和删除也用foreach搞定,样子如下:


  
  
  1. <delete id="batchDeleteStudentWithList" parameterType="java.util.List">
  2. <foreach collection="list" item="item" index="index" open="" close="" separator=";">
  3. DELETE FROM t_student
  4. where id=#{item.id}
  5. </foreach>
  6. </delete>
  7. <update id="batchUpdateByIdList" parameterType="java.util.List">
  8. UPDATE t_student set name='test' where id in
  9. <foreach collection="list" item="idItem" index="index" open="("
  10. separator= "," close= ")">
  11. #{idItem}
  12. </foreach>
  13. </update>
4、第四题,你对Redis的理解,Redis在项目中你怎么用的?Redis为什么这么快,qps有多少?

Redis是一种缓存框架,将经常需要查询的数据缓存起来,便于提高对数据库的查询效率,同时减轻数据库负担的缓存技术。其他缓存技术,如Ecache等。Redis在项目中怎么用的自己看着说吧,与spring集成的。回答第三问,首先解释下qps的意思,每秒钟可以处理的查询的次数,QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。那为什么一秒钟redis可以处理高达上万次查询呢?第一,Redis大部分查询都是基于内存的,内存和到数据直接查询速度没法比;第二,Redis是基于单线程的,也就是即使非常多查询到来,Redis也是一个线程应付,这样线程切换和竞争锁的消耗就没了。第三,虽然单线程但是Redis是no-blocking,也就是IO非阻塞方式,意味着一个查询如果产生阻塞,不会等待,而会马上处理下一个,等到第一个查询可以正常IO了再进行。这样qps自然会很大。

5.第五题,数据库读写分离谈一下。参考博文:http://blog.csdn.net/wonderful_life_mrchi/article/details/77778270

6.第六题,有些公司喜欢问java IO和NIO的比较。其实io我们都知道,就是输入输出流,socket聊天室项目接触过,如果输入流有内容就读取,没有就阻塞,直到客户端发来消息,继续读取,而且还要为每一个客户端开启一个线程。如果用户数目很多,就会产生很多线程,增加了线程的开销。其实java早在1.4版本就有这种io技术,那个包java.nio,这个面试题具体答案:http://blog.csdn.net/wonderful_life_mrchi/article/details/77778423

当然如果后续详细学习nio,也就是非阻塞IO,可以参照本人三篇nio的博文。这道题,不好好看看真不好回答。关于非阻塞这样的名词还是要恶补一下的。

7.大家记得Dubbo吗?具体使用见本人Dubbo官方入门博文:http://blog.csdn.net/wonderful_life_mrchi/article/details/77148699,但这里面不是用zookeeper注册的服务,而是用多播技术。如果用zookeeper方式,zookeeper在Dubbo中的作用是什么?面试题就是这样问的。

答案:zookeeper保存了服务提供方和服务消费方的的URI(dubbo自定义的一种URI),服务消费方找到zookeeper,向zookeeper要到服务提供方的URI,然后就找到提供方,并调用提供方的服务。也就是说服务提供方,将自己的url给zookeeper,有人要用服务的话就向zk要,zk给你一个网址,然后你再去网址访问真正的服务,zk充当一个存储服务地址信息小数据库的角色。

8.这道题依然是zookeeper的,更难一些了,zk的分布式事务是怎么实现的?

zookeeper真正使用是需要至少有三个节点的集群的,zk三个节点之间互相同步记录的信息。其中有一个是主节点,其他从节点。当有一个挂了,其他两个投票选择一个作为主节点,当就剩下一个时,就真挂了。这些与本问题无关,只是说一下zk是需要多个分布式节点的。

回到问题的答案:

完全分布式锁是全局同步的,这意味着在任何时刻没有两个客户端会同时认为它们都拥有相同的锁,使用 Zookeeper 可以实现分布式锁,需要首先定义一个锁节点(lock root node)。

需要获得锁的客户端按照以下步骤来获取锁:

  1. 保证锁节点(lock root node)这个父根节点的存在,这个节点是每个要获取lock客户端共用的,这个节点是PERSISTENT的。
  2. 第一次需要创建本客户端要获取lock的节点,调用 create( ),并设置 节点为EPHEMERAL_SEQUENTIAL类型,表示该节点为临时的和顺序的。如果获取锁的节点挂掉,则该节点自动失效,可以让其他节点获取锁。

  3. 在父锁节点(lock root node)上调用 getChildren( ) ,不需要设置监视标志。 (为了避免“羊群效应”).

  4. 按照Fair竞争的原则,将步骤3中的子节点(要获取锁的节点)按照节点顺序的大小做排序,取出编号最小的一个节点做为lock的owner,判断自己的节点id
    是否就为owner id,如果是则返回,lock成功。如果不是则调用 exists( )监听比自己小的前一位的id,关注它锁释放的操作(也就是exist watch)。

  5. 如果第4步监听exist的watch被触发,则继续按4中的原则判断自己是否能获取到lock。

释放锁:需要释放锁的客户端只需要删除在第2步中创建的节点即可。

总结,这里的问题有的是学过的,但是问的比较细化和深入,有的就是跟大数据或者高并发处理有关,所以大家还是多注意留心这方面面试题。这里关于spring框架的就没有再写了,太多了,诸如ioc,aop,springmvc工作机制,都是基本的,做过项目都能说个差不多,实在不行,百度一下吧。关于面试,就说这些了。

最后,希望小伙伴们,用自信的底气打动考官,用真诚好学的态度融化他们,用迷人的笑容陶醉他们,用一往无前的勇气征服他们!!!祝各位,求职成功。





猜你喜欢

转载自blog.csdn.net/rj151YY/article/details/84372367