1. 程式人生 > >javaEE工程師面試題(高階部分)

javaEE工程師面試題(高階部分)

java工程師,你需要知道的還有很多!如今的Web工程師,不僅要懂java基礎,框架,servlet,前端,還要會各種框架整合,什麼ssh,ssm.....諸如此類吧。不可否認,這些是根基,但要作為一個高階工程師,面試必然會問到的還包括如下一些,大家好好準備下。

先來個框架的

1.mybatis是如何將結果集對映為物件的?

首先,mybatis是對jdbc的封裝,再怎麼樣也是查出結果集然後用一個ResultSetHandler將結果集對映為我們定義的比如User這樣的物件,但屬性和列名如何對應呢?

大家應該都記得吧,有兩種:

Mybatis的輸出對映,也就是對查詢結果集的一個對映,主要有兩種:

    1.resultType(不需要配置,可以直接用),這種方式必須保證列名和屬性名完全一樣才能自動配上,要麼寫得SQL就要用as起別名

      一般是實體類

      基本型別也可以

    2.resultMap(需要配置resultMap與之對應)

     還記得咋寫嗎?這樣:


  
  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工作機制,都是基本的,做過專案都能說個差不多,實在不行,百度一下吧。關於面試,就說這些了。

最後,希望小夥伴們,用自信的底氣打動考官,用真誠好學的態度融化他們,用迷人的笑容陶醉他們,用一往無前的勇氣征服他們!!!祝各位,求職成功。