超全面Java 面試題(2.1)

來源:互聯網
上載者:User

標籤:業務   模式   order   data   全面   sdn   隊列   arc   namespace   

這部分主要是開源JavaEE架構方面的內容,包括hibernate、MyBatis、spring、Spring MVC等,由於Struts2已經是明日黃花,在這裡就不討論Struts2的面試題,此外,這篇文章還對公司專屬應用程式架構、大型網站架構和應用伺服器最佳化等內容進行了簡單的探討,這些內容相信對面試會很有協助。

 

126、什麼是ORM?

答:對象關係映射(Object-Relational Mapping,簡稱ORM)是一種為瞭解決程式的物件導向模型與資料庫的關聯式模式互不匹配問題的技術;簡單的說,ORM是通過使用描述對象和資料庫之間映射的中繼資料(在Java中可以用XML或者是註解),將程式中的對象自動持久化到關聯式資料庫中或者將關聯式資料庫表中的行轉換成Java對象,其本質上就是將資料從一種形式轉換到另外一種形式。

127、持久層設計要考慮的問題有哪些?你用過的持久層架構有哪些?

答:所謂”持久”就是將資料儲存到可掉電式存放裝置中以便今後使用,簡單的說,就是將記憶體中的資料儲存到關係型資料庫、檔案系統、訊息佇列等提供持久化支援的裝置中。持久層就是系統中專註於實現資料持久化的相對獨立的層面。

持久層設計的目標包括:

- 資料存放區邏輯的分離,提供抽象化的資料提供者。

- 資料訪問底層實現的分離,可以在不修改代碼的情況下切換底層實現。

- 資源管理和調度的分離,在資料訪問層實現統一的資源調度(如緩衝機制)。

- 資料抽象,提供更物件導向的資料操作。

持久層架構有:

- Hibernate

- MyBatis

- TopLink

- Guzz

- jOOQ

- Spring Data

- ActiveJDBC

128、Hibernate中SessionFactory是安全執行緒的嗎?Session是安全執行緒的嗎(兩個線程能夠共用同一個Session嗎)?

答:SessionFactory對應Hibernate的一個資料存放區的概念,它是安全執行緒的,可以被多個線程並發訪問。SessionFactory一般只會在啟動的時候構建。對於應用程式,最好將SessionFactory通過單例模式進行封裝以便於訪問。Session是一個輕量級非安全執行緒的對象(線程間不能共用session),它表示與資料庫進行互動的一個工作單元。Session是由SessionFactory建立的,在任務完成之後它會被關閉。Session是持久層服務對外提供的主要介面。Session會延遲擷取資料庫連接(也就是在需要的時候才會擷取)。為了避免建立太多的session,可以使用ThreadLocal將session和當前線程綁定在一起,這樣可以讓同一個線程獲得的總是同一個session。Hibernate 3中SessionFactory的getCurrentSession()方法就可以做到。

129、Hibernate中Session的load和get方法的區別是什嗎?

答:主要有以下三項區別:

① 如果沒有找到合格記錄,get方法返回null,load方法拋出異常。

② get方法直接返回實體類對象,load方法返回實體類對象的代理。

③ 在Hibernate 3之前,get方法只在一級緩衝中進行資料尋找,如果沒有找到

對應的資料則越過二級緩衝,直接發出SQL陳述式完成資料讀取;load方法則可以從二級緩衝中擷取資料;從Hibernate 3開始,get方法不再是對二級緩衝唯寫不讀,它也是可以訪問二級緩衝的。

說明:對於load()方法Hibernate認為該資料在資料庫中一定存在可以放心的使用代理來實現消極式載入,如果沒有資料就拋出異常,而通過get()方法擷取的資料可以不存在。

130、Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分別是做什麼的?有什麼區別?

答:Hibernate的對象有三種狀態:瞬時態(transient)、持久態(persistent)和游離態(detached),如第135題中的圖所示。瞬時態的執行個體可以通過調用save()、persist()或者saveOrUpdate()方法變成持久態;游離態的執行個體可以通過調用 update()、saveOrUpdate()、lock()或者replicate()變成持久態。save()和persist()將會引發SQL的INSERT語句,而update()或merge()會引發UPDATE語句。save()和update()的區別在於一個是將瞬時態對象變成持久態,一個是將游離態對象變為持久態。merge()方法可以完成save()和update()方法的功能,它的意圖是將新的狀態合并到已有的持久化對象上或建立新的持久化對象。對於persist()方法,按照官方文檔的說明:① persist()方法把一個瞬時態的執行個體持久化,但是並不保證標識符被立刻填入到持久化執行個體中,標識符的填入可能被延遲到flush的時間;② persist()方法保證當它在一個事務外部被調用的時候並不觸發一個INSERT語句,當需要封裝一個長會話流程的時候,persist()方法是很有必要的;③ save()方法不保證第②條,它要返回標識符,所以它會立即執行INSERT語句,不管是在事務內部還是外部。至於lock()方法和update()方法的區別,update()方法是把一個已經更改過的脫管狀態的對象變成持久狀態;lock()方法是把一個沒有更改過的脫管狀態的對象變成持久狀態。

131、闡述Session載入實體物件的過程。

答:Session載入實體物件的步驟是:

① Session在調用資料庫查詢功能之前,首先會在一級緩衝中通過實體類型和主鍵進行尋找,如果一級緩衝尋找命中且資料狀態合法,則直接返回;

② 如果一級緩衝沒有命中,接下來Session會在當前NonExists記錄(相當於一個查詢黑名單,如果出現重複的無效查詢可以迅速做出判斷,從而提升效能)中進行尋找,如果NonExists中存在同樣的查詢條件,則返回null;

③ 如果一級緩衝查詢失敗則查詢二級緩衝,如果二級快取命中則直接返回;

④ 如果之前的查詢都未命中,則發出SQL語句,如果查詢未發現對應記錄則將此次查詢添加到Session的NonExists中加以記錄,並返回null;

⑤ 根據映射配置和SQL語句得到ResultSet,並建立對應的實體物件;

⑥ 將對象納入Session(一級緩衝)的管理;

⑦ 如果有對應的攔截器,則執行攔截器的onLoad方法;

⑧ 如果開啟並設定了要使用二級緩衝,則將資料對象納入二級緩衝;

⑨ 返回資料對象。

132、Query介面的list方法和iterate方法有什麼區別?

答:

① list()方法無法利用一級緩衝和二級緩衝(對緩衝唯寫不讀),它只能在開啟查詢快取的前提下使用查詢快取;iterate()方法可以充分利用緩衝,如果目標資料唯讀或者讀取頻繁,使用iterate()方法可以減少效能開銷。

② list()方法不會引起N+1查詢問題,而iterate()方法可能引起N+1查詢問題

說明:關於N+1查詢問題,可以參考CSDN上的一篇文章《什麼是N+1查詢》

133、Hibernate如何?分頁查詢?

答:通過Hibernate實現分頁查詢,開發人員只需要提供HQL語句(調用Session的createQuery()方法)或查詢條件(調用Session的createCriteria()方法)、設定查詢起始行數(調用Query或Criteria介面的setFirstResult()方法)和最大查詢行數(調用Query或Criteria介面的setMaxResults()方法),並調用Query或Criteria介面的list()方法,Hibernate會自動產生分頁查詢的SQL語句。

134、鎖機制有什麼用?簡述Hibernate的悲觀鎖和樂觀鎖機制。

答:有些商務邏輯在執行過程中要求對資料進行排他性的訪問,於是需要通過一些機制保證在此過程中資料被鎖住不會被外界修改,這就是所謂的鎖機制。

Hibernate支援悲觀鎖和樂觀鎖兩種鎖機制。悲觀鎖,顧名思義悲觀的認為在資料處理過程中極有可能存在修改資料的並發事務(包括本系統的其他事務或來自外部系統的事務),於是將處理的資料設定為鎖定狀態。悲觀鎖必須依賴資料庫本身的鎖機制才能真正保證資料訪問的排他性,關於資料庫的鎖機制和交易隔離等級在《Java面試題大全(上)》中已經討論過了。樂觀鎖,顧名思義,對並發事務持樂觀態度(認為對資料的並行作業不會經常性的發生),通過更加寬鬆的鎖機制來解決由於悲觀鎖排他性的資料訪問對系統效能造成的嚴重影響。最常見的樂觀鎖是通過資料版本標識來實現的,讀取資料時獲得資料的版本號碼,更新資料時將此版本號碼加1,然後和資料庫表對應記錄的目前的版本號進行比較,如果提交的資料版本號碼大於資料庫中此記錄的目前的版本號則更新資料,否則認為是到期資料無法更新。Hibernate中通過Session的get()和load()方法從資料庫中載入對象時可以通過參數指定使用悲觀鎖;而樂觀鎖可以通過給實體類加整型的版本欄位再通過XML或@Version註解進行配置。

提示:使用樂觀鎖會增加了一個版本欄位,很明顯這需要額外的空間來儲存這個版本欄位,浪費了空間,但是樂觀鎖會讓系統具有更好的並發性,這是對時間的節省。因此樂觀鎖也是典型的空間換時間的策略。

135、闡述實體物件的三種狀態以及轉換關係。

答:最新的Hibernate文檔中為Hibernate對象定義了四種狀態(原來是三種狀態,面試的時候基本上問的也是三種狀態),分別是:瞬時態(new, or transient)、持久態(managed, or persistent)、遊狀態(detached)和移除態(removed,以前Hibernate文檔中定義的三種狀態中沒有移除態),如所示,就以前的Hibernate文檔中移除態被視為是瞬時態。

瞬時態:當new一個實體物件後,這個對象處於瞬時態,即這個對象只是一個儲存臨時資料的記憶體地區,如果沒有變數引用這個對象,則會被JVM的記憶體回收機制回收。這個對象所儲存的資料與資料庫沒有任何關係,除非通過Session的save()、saveOrUpdate()、persist()、merge()方法把瞬時態對象與資料庫關聯,並把資料插入或者更新到資料庫,這個對象才轉換為持久態對象。

持久態:持久態對象的執行個體在資料庫中有對應的記錄,並擁有一個持久化標識(ID)。對持久態對象進行delete操作後,資料庫中對應的記錄將被刪除,那麼持久態對象與資料庫記錄不再存在對應關係,持久態對象變成移除態(可以視為瞬時態)。持久態對象被修改變更後,不會馬上同步到資料庫,直到資料庫事務提交。

游離態:當Session進行了close()、clear()、evict()或flush()後,實體物件從持久態變成游離態,對象雖然擁有持久和與資料庫對應記錄一致的標識值,但是因為對象已經從會話中清除掉,對象不在持久化管理之內,所以處於游離態(也叫脫管態)。游離態的對象與臨時狀態物件是十分相似的,只是它還含有持久化標識。

提示:關於這個問題,在Hibernate的官方文檔中有更為詳細的解讀。

136、如何理解Hibernate的消極式載入機制?在實際應用中,消極式載入與Session關閉的矛盾是如何處理的?

答:消極式載入就是並不是在讀取的時候就把資料載入進來,而是等到使用時再載入。Hibernate使用了虛擬代理機制實現消極式載入,我們使用Session的load()方法載入資料或者一對多關聯映射在使用消極式載入的情況下從一的一方載入多的一方,得到的都是虛擬代理,簡單的說返回給使用者的並不是實體本身,而是實體物件的代理。代理對象在使用者調用getter方法時才會去資料庫載入資料。但載入資料就需要資料庫連接。而當我們把會話關閉時,資料庫連接就同時關閉了。

消極式載入與session關閉的矛盾一般可以這樣處理:

① 關閉消極式載入特性。這種方式操作起來比較簡單,因為Hibernate的消極式載入特性是可以通過對應檔或者註解進行配置的,但這種解決方案存在明顯的缺陷。首先,出現”no session or session was closed”通常說明系統中已經存在主外部索引鍵關聯,如果去掉消極式載入的話,每次查詢的開銷都會變得很大。

② 在session關閉之前先擷取需要查詢的資料,可以使用工具方法Hibernate.isInitialized()判斷對象是否被載入,如果沒有被載入則可以使用Hibernate.initialize()方法載入對象。

③ 使用攔截器或過濾器延長Session的生命週期直到視圖獲得資料。Spring整合Hibernate提供的OpenSessionInViewFilter和OpenSessionInViewInterceptor就是這種做法。

137、舉一個多對多關聯的例子,並說明如何?多對多關聯映射。

答:例如:商品和訂單、學生和課程都是典型的多對多關係。可以在實體類上通過@ManyToMany註解配置多對多關聯或者通過對應檔中的和標籤配置多對多關聯,但是實際項目開發中,很多時候都是將多對多關聯映射轉換成兩個多對一關聯映射來實現的。

138、談一下你對繼承映射的理解。

答:繼承關係的映射策略有三種:

① 每個繼承結構一張表(table per class hierarchy),不管多少個子類都用一張表。

② 每個子類一張表(table per subclass),公用資訊放一張表,特有資訊放單獨的表。

③ 每個具體類一張表(table per concrete class),有多少個子類就有多少張表。

第一種方式屬於單表策略,其優點在於查詢子類對象的時候無需表串連,查詢速度快,適合多態查詢;缺點是可能導致表很大。後兩種方式屬於多表策略,其優點在於資料存放區緊湊,其缺點是需要進行串連查詢,不適合多態查詢。

139、簡述Hibernate常見最佳化策略。

答:這個問題應當挑自己使用過的最佳化策略回答,常用的有:

① 制定合理的緩衝策略(二級緩衝、查詢快取)。

② 採用合理的Session管理機制。

③ 盡量使用消極式載入特性。

④ 設定合理的批處理參數。

⑤ 如果可以,選用UUID作為主鍵產生器。

⑥ 如果可以,選用基於版本號碼的樂觀鎖替代悲觀鎖。

⑦ 在開發過程中, 開啟hibernate.show_sql選項查看產生的SQL,從而瞭解底層的狀況;開發完成後關閉此選項。

⑧ 考慮資料庫本身的最佳化,合理的索引、恰當的資料分區策略等都會對持久層的效能帶來可觀的提升,但這些需要專業的DBA(資料庫管理員)提供支援。

140、談一談Hibernate的一級緩衝、二級緩衝和查詢快取。

答:Hibernate的Session提供了一級緩衝的功能,預設總是有效,當應用程式儲存持久化實體、修改持久化實體時,Session並不會立即把這種改變提交到資料庫,而是緩衝在當前的Session中,除非顯示調用了Session的flush()方法或通過close()方法關閉Session。通過一級緩衝,可以減少程式與資料庫的互動,從而提高資料庫訪問效能。

SessionFactory層級的二級緩衝是全域性的,所有的Session可以共用這個二級緩衝。不過二級緩衝預設是關閉的,需要顯示開啟並指定需要使用哪種二級緩衝實作類別(可以使用第三方提供的實現)。一旦開啟了二級緩衝並設定了需要使用二級緩衝的實體類,SessionFactory就會緩衝訪問過的該實體類的每個對象,除非緩衝的資料超出了指定的緩衝空間。

一級緩衝和二級緩衝都是對整個實體進行緩衝,不會緩衝普通屬性,如果希望對普通屬性進行緩衝,可以使用查詢快取。查詢快取是將HQL或SQL語句以及它們的查詢結果作為索引值對進行緩衝,對於同樣的查詢可以直接從緩衝中擷取資料。查詢快取預設也是關閉的,需要顯示開啟。

141、Hibernate中DetachedCriteria類是做什麼的?

答:DetachedCriteria和Criteria的用法基本上是一致的,但Criteria是由Session的createCriteria()方法建立的,也就意味著離開建立它的Session,Criteria就無法使用了。DetachedCriteria不需要Session就可以建立(使用DetachedCriteria.forClass()方法建立),所以通常也稱其為離線的Criteria,在需要進行查詢操作的時候再和Session綁定(調用其getExecutableCriteria(Session)方法),這也就意味著一個DetachedCriteria可以在需要的時候和不同的Session進行綁定。

142、@OneToMany註解的mappedBy屬性有什麼作用?

答:@OneToMany用來配置一對多關聯映射,但通常情況下,一對多關聯映射都由多的一方來維護關聯關係,例如學生和班級,應該在學生類中添加班級屬性來維持學生和班級的關聯關係(在資料庫中是由學生表中的外鍵班級編號來維護學生表和班級表的多對一關聯性),如果要使用雙向關聯,在班級類中添加一個容器屬性來存放學生,並使用@OneToMany註解進行映射,此時mappedBy屬性就非常重要。如果使用XML進行配置,可以用標籤的inverse=”true”設定來達到同樣的效果。

143、MyBatis中使用#和$書寫預留位置有什麼區別?

答:#將傳入的資料都當成一個字串,會對傳入的資料自動加上引號;$將傳入的資料直接顯示產生在SQL中。注意:使用$預留位置可能會導致SQL注射攻擊,能用#的地方就不要使用$,寫order by子句的時候應該用$而不是#。

144、解釋一下MyBatis中命名空間(namespace)的作用。

答:在大型項目中,可能存在大量的SQL語句,這時候為每個SQL語句起一個唯一的標識(ID)就變得並不容易了。為瞭解決這個問題,在MyBatis中,可以為每個對應檔起一個唯一的命名空間,這樣定義在這個對應檔中的每個SQL語句就成了定義在這個命名空間中的一個ID。只要我們能夠保證每個命名空間中這個ID是唯一的,即使在不同對應檔中的語句ID相同,也不會再產生衝突了。

145、MyBatis中的動態SQL是什麼意思?

答:對於一些複雜的查詢,我們可能會指定多個查詢條件,但是這些條件可能存在也可能不存在,例如在58同城上面找房子,我們可能會指定面積、樓層和所在位置來尋找房源,也可能會指定面積、價格、戶型和所在位置來尋找房源,此時就需要根據使用者指定的條件動態產生SQL語句。如果不使用持久層架構我們可能需要自己拼裝SQL語句,還好MyBatis提供了動態SQL的功能來解決這個問題。MyBatis中用於實現動態SQL的元素主要有:

- if

- choose / when / otherwise

- trim

- where

- set

- foreach

下面是對應檔的片段。

select * from t_blog where 1 = 1

and title = #{title}

and content = #{content}

and owner = #{owner}

當然也可以像下面這些書寫。

select * from t_blog where 1 = 1

and title = #{title}

and content = #{content}

and owner = "owner1"

再看看下面這個例子。

select * from t_blog where id in

item="item" open="(" separator="," close=")">

#{item}

超全面Java 面試題(2.1)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.