1. 程式人生 > 實用技巧 >java面試題(二)

java面試題(二)

第九模組

設計模式

88. 說一下你熟悉的設計模式?

參考:常用的設計模式彙總,超詳細!

89. 簡單工廠和抽象工廠有什麼區別?

簡單工廠模式

這個模式本身很簡單而且使用在業務較簡單的情況下。一般用於小專案或者具體產品很少擴充套件的情況(這樣工廠類才不用經常更改)。

它由三種角色組成:

  • 工廠類角色:這是本模式的核心,含有一定的商業邏輯和判斷邏輯,根據邏輯不同,產生具體的工廠產品。如例子中的Driver類。
  • 抽象產品角色:它一般是具體產品繼承的父類或者實現的介面。由介面或者抽象類來實現。如例中的Car介面。
  • 具體產品角色:工廠類所建立的物件就是此角色的例項。在java中由一個具體類實現,如例子中的Benz、Bmw類。

來用類圖來清晰的表示下的它們之間的關係:

抽象工廠模式:

先來認識下什麼是產品族: 位於不同產品等級結構中,功能相關聯的產品組成的家族。

圖中的BmwCar和BenzCar就是兩個產品樹(產品層次結構);而如圖所示的BenzSportsCar和BmwSportsCar就是一個產品族。他們都可以放到跑車家族中,因此功能有所關聯。同理BmwBussinessCar和BenzBusinessCar也是一個產品族。

可以這麼說,它和工廠方法模式的區別就在於需要建立物件的複雜程度上。而且抽象工廠模式是三個裡面最為抽象、最具一般性的。抽象工廠模式的用意為:給客戶端提供一個介面,可以建立多個產品族中的產品物件。

而且使用抽象工廠模式還要滿足一下條件:

  1. 系統中有多個產品族,而系統一次只可能消費其中一族產品
  2. 同屬於同一個產品族的產品以其使用。

來看看抽象工廠模式的各個角色(和工廠方法的如出一轍):

  • 抽象工廠角色: 這是工廠方法模式的核心,它與應用程式無關。是具體工廠角色必須實現的介面或者必須繼承的父類。在java中它由抽象類或者介面來實現。
  • 具體工廠角色:它含有和具體業務邏輯有關的程式碼。由應用程式呼叫以建立對應的具體產品的物件。在java中它由具體的類來實現。
  • 抽象產品角色:它是具體產品繼承的父類或者是實現的介面。在java中一般有抽象類或者介面來實現。
  • 具體產品角色:具體工廠角色所建立的物件就是此角色的例項。在java中由具體的類來實現。

第十模組

Spring / Spring MVC

90. 為什麼要使用 spring?

1.簡介

  • 目的:解決企業應用開發的複雜性
  • 功能:使用基本的JavaBean代替EJB,並提供了更多的企業應用功能
  • 範圍:任何Java應用

簡單來說,Spring是一個輕量級的控制反轉(IoC)和麵向切面(AOP)的容器框架。

2.輕量  

從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小隻有1MB多的JAR檔案裡釋出。並且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的物件不依賴於Spring的特定類。

3.控制反轉  

Spring通過一種稱作控制反轉(IoC)的技術促進了鬆耦合。當應用了IoC,一個物件依賴的其它物件會通過被動的方式傳遞進來,而不是這個物件自己建立或者查詢依賴物件。你可以認為IoC與JNDI相反——不是物件從容器中查詢依賴,而是容器在物件初始化時不等物件請求就主動將依賴傳遞給它。

4.面向切面  

Spring提供了面向切面程式設計的豐富支援,允許通過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發。應用物件只實現它們應該做的——完成業務邏輯——僅此而已。它們並不負責(甚至是意識)其它的系統級關注點,例如日誌或事務支援。

5.容器

Spring包含並管理應用物件的配置和生命週期,在這個意義上它是一種容器,你可以配置你的每個bean如何被建立——基於一個可配置原型(prototype),你的bean可以建立一個單獨的例項或者每次需要時都生成一個新的例項——以及它們是如何相互關聯的。然而,Spring不應該被混同於傳統的重量級的EJB容器,它們經常是龐大與笨重的,難以使用。

6.框架

Spring可以將簡單的元件配置、組合成為複雜的應用。在Spring中,應用物件被宣告式地組合,典型地是在一個XML檔案裡。Spring也提供了很多基礎功能(事務管理、持久化框架整合等等),將應用邏輯的開發留給了你。

所有Spring的這些特徵使你能夠編寫更乾淨、更可管理、並且更易於測試的程式碼。它們也為Spring中的各種模組提供了基礎支援。

91. 解釋一下什麼是 aop?

AOP(Aspect-Oriented Programming,面向方面程式設計),可以說是OOP(Object-Oriented Programing,面向物件程式設計)的補充和完善。OOP引入封裝、繼承和多型性等概念來建立一種物件層次結構,用以模擬公共行為的一個集合。當我們需要為分散的物件引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關係,但並不適合定義從左到右的關係。例如日誌功能。日誌程式碼往往水平地散佈在所有物件層次中,而與它所散佈到的物件的核心功能毫無關係。對於其他型別的程式碼,如安全性、異常處理和透明的持續性也是如此。這種散佈在各處的無關的程式碼被稱為橫切(cross-cutting)程式碼,在OOP設計中,它導致了大量程式碼的重複,而不利於各個模組的重用。

而AOP技術則恰恰相反,它利用一種稱為“橫切”的技術,剖解開封裝的物件內部,並將那些影響了多個類的公共行為封裝到一個可重用模組,並將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模組所共同呼叫的邏輯或責任封裝起來,便於減少系統的重複程式碼,降低模組間的耦合度,並有利於未來的可操作性和可維護性。AOP代表的是一個橫向的關係,如果說“物件”是一個空心的圓柱體,其中封裝的是物件的屬性和行為;那麼面向方面程式設計的方法,就彷彿一把利刃,將這些空心圓柱體剖開,以獲得其內部的訊息。而剖開的切面,也就是所謂的“方面”了。然後它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。

使用“橫切”技術,AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如許可權認證、日誌、事務處理。Aop 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。正如Avanade公司的高階方案構架師Adam Magee所說,AOP的核心思想就是“將應用程式中的商業邏輯同對其提供支援的通用服務進行分離。”

92. 解釋一下什麼是 ioc?

IOC是Inversion of Control的縮寫,多數書籍翻譯成“控制反轉”。

  

1996年,Michael Mattson在一篇有關探討面向物件框架的文章中,首先提出了IOC 這個概念。對於面向物件設計及程式設計的基本思想,前面我們已經講了很多了,不再贅述,簡單來說就是把複雜系統分解成相互合作的物件,這些物件類通過封裝以後,內部實現對外部是透明的,從而降低了解決問題的複雜度,而且可以靈活地被重用和擴充套件。

  

IOC理論提出的觀點大體是這樣的:藉助於“第三方”實現具有依賴關係的物件之間的解耦。如下圖:

圖 IOC解耦過程

  

大家看到了吧,由於引進了中間位置的“第三方”,也就是IOC容器,使得A、B、C、D這4個物件沒有了耦合關係,齒輪之間的傳動全部依靠“第三方”了,全部物件的控制權全部上繳給“第三方”IOC容器,所以,IOC容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有物件粘合在一起發揮作用,如果沒有這個“粘合劑”,物件與物件之間會彼此失去聯絡,這就是有人把IOC容器比喻成“粘合劑”的由來。

  

我們再來做個試驗:把上圖中間的IOC容器拿掉,然後再來看看這套系統:

圖 拿掉IOC容器後的系統

  

我們現在看到的畫面,就是我們要實現整個系統所需要完成的全部內容。這時候,A、B、C、D這4個物件之間已經沒有了耦合關係,彼此毫無聯絡,這樣的話,當你在實現A的時候,根本無須再去考慮B、C和D了,物件之間的依賴關係已經降低到了最低程度。所以,如果真能實現IOC容器,對於系統開發而言,這將是一件多麼美好的事情,參與開發的每一成員只要實現自己的類就可以了,跟別人沒有任何關係!

我們再來看看,控制反轉(IOC)到底為什麼要起這麼個名字?我們來對比一下:

軟體系統在沒有引入IOC容器之前,如圖1所示,物件A依賴於物件B,那麼物件A在初始化或者執行到某一點的時候,自己必須主動去建立物件B或者使用已經建立的物件B。無論是建立還是使用物件B,控制權都在自己手上。

軟體系統在引入IOC容器之後,這種情形就完全改變了,如圖3所示,由於IOC容器的加入,物件A與物件B之間失去了直接聯絡,所以,當物件A執行到需要物件B的時候,IOC容器會主動建立一個物件B注入到物件A需要的地方。

通過前後的對比,我們不難看出來:物件A獲得依賴物件B的過程,由主動行為變為了被動行為,控制權顛倒過來了,這就是“控制反轉”這個名稱的由來。

93. spring 有哪些主要模組?

Spring框架至今已集成了20多個模組。這些模組主要被分如下圖所示的核心容器、資料訪問/整合,、Web、AOP(面向切面程式設計)、工具、訊息和測試模組。

更多資訊:howtodoinjava.com/java-spring-framework-tutorials/

94. spring 常用的注入方式有哪些?

Spring通過DI(依賴注入)實現IOC(控制反轉),常用的注入方式主要有三種:

  1. 構造方法注入
  2. setter注入
  3. 基於註解的注入

95. spring 中的 bean 是執行緒安全的嗎?

Spring容器中的Bean是否執行緒安全,容器本身並沒有提供Bean的執行緒安全策略,因此可以說spring容器中的Bean本身不具備執行緒安全的特性,但是具體還是要結合具體scope的Bean去研究。

96. spring 支援幾種 bean 的作用域?

當通過spring容器建立一個Bean例項時,不僅可以完成Bean例項的例項化,還可以為Bean指定特定的作用域。Spring支援如下5種作用域:

  • singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的Bean將只有一個例項
  • prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新的Bean例項
  • request:對於每次HTTP請求,使用request定義的Bean都將產生一個新例項,即每次HTTP請求將會產生不同的Bean例項。只有在Web應用中使用Spring時,該作用域才有效
  • session:對於每次HTTP Session,使用session定義的Bean豆漿產生一個新例項。同樣只有在Web應用中使用Spring時,該作用域才有效
  • globalsession:每個全域性的HTTP Session,使用session定義的Bean都將產生一個新例項。典型情況下,僅在使用portlet context的時候有效。同樣只有在Web應用中使用Spring時,該作用域才有效

其中比較常用的是singleton和prototype兩種作用域。對於singleton作用域的Bean,每次請求該Bean都將獲得相同的例項。容器負責跟蹤Bean例項的狀態,負責維護Bean例項的生命週期行為;如果一個Bean被設定成prototype作用域,程式每次請求該id的Bean,Spring都會新建一個Bean例項,然後返回給程式。在這種情況下,Spring容器僅僅使用new 關鍵字建立Bean例項,一旦建立成功,容器不在跟蹤例項,也不會維護Bean例項的狀態。

如果不指定Bean的作用域,Spring預設使用singleton作用域。Java在建立Java例項時,需要進行記憶體申請;銷燬例項時,需要完成垃圾回收,這些工作都會導致系統開銷的增加。因此,prototype作用域Bean的建立、銷燬代價比較大。而singleton作用域的Bean例項一旦建立成功,可以重複使用。因此,除非必要,否則儘量避免將Bean被設定成prototype作用域。

97. spring 自動裝配 bean 有哪些方式?

Spring容器負責建立應用程式中的bean同時通過ID來協調這些物件之間的關係。作為開發人員,我們需要告訴Spring要建立哪些bean並且如何將其裝配到一起。

spring中bean裝配有兩種方式:

  • 隱式的bean發現機制和自動裝配
  • 在java程式碼或者XML中進行顯示配置

當然這些方式也可以配合使用。

98. spring 事務實現方式有哪些?

  1. 程式設計式事務管理對基於 POJO 的應用來說是唯一選擇。我們需要在程式碼中呼叫beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是程式設計式事務管理。
  2. 基於 TransactionProxyFactoryBean 的宣告式事務管理
  3. 基於 @Transactional 的宣告式事務管理
  4. 基於 Aspectj AOP 配置事務

99. 說一下 spring 的事務隔離?

事務隔離級別指的是一個事務對資料的修改與另一個並行的事務的隔離程度,當多個事務同時訪問相同資料時,如果沒有采取必要的隔離機制,就可能發生以下問題:

  • 髒讀:一個事務讀到另一個事務未提交的更新資料。
  • 幻讀:例如第一個事務對一個表中的資料進行了修改,比如這種修改涉及到表中的“全部資料行”。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入“一行新資料”。那麼,以後就會發生操作第一個事務的使用者發現表中還存在沒有修改的資料行,就好象發生了幻覺一樣。
  • 不可重複讀:比方說在同一個事務中先後執行兩條一模一樣的select語句,期間在此次事務中沒有執行過任何DDL語句,但先後得到的結果不一致,這就是不可重複讀。

100. 說一下 spring mvc 執行流程?

Spring MVC執行流程圖:

Spring執行流程描述:

\1. 使用者向伺服器傳送請求,請求被Spring 前端控制Servelt DispatcherServlet捕獲;

\2. DispatcherServlet對請求URL進行解析,得到請求資源識別符號(URI)。然後根據該URI,呼叫HandlerMapping獲得該Handler配置的所有相關的物件(包括Handler物件以及Handler物件對應的攔截器),最後以HandlerExecutionChain物件的形式返回;

\3. DispatcherServlet 根據獲得的Handler,選擇一個合適的HandlerAdapter;(附註:如果成功獲得HandlerAdapter後,此時將開始執行攔截器的preHandler(...)方法)

\4. 提取Request中的模型資料,填充Handler入參,開始執行Handler(Controller)。 在填充Handler的入參過程中,根據你的配置,Spring將幫你做一些額外的工作:

  • HttpMessageConveter: 將請求訊息(如Json、xml等資料)轉換成一個物件,將物件轉換為指定的響應資訊

  • 資料轉換:對請求訊息進行資料轉換。如String轉換成Integer、Double等

  • 資料根式化:對請求訊息進行資料格式化。 如將字串轉換成格式化數字或格式化日期等

  • 資料驗證: 驗證資料的有效性(長度、格式等),驗證結果儲存到BindingResult或Error中

\5. Handler執行完成後,向DispatcherServlet 返回一個ModelAndView物件;

\6. 根據返回的ModelAndView,選擇一個適合的ViewResolver(必須是已經註冊到Spring容器中的ViewResolver)返回給DispatcherServlet ;

\7. ViewResolver 結合Model和View,來渲染檢視;

\8. 將渲染結果返回給客戶端。

101. spring mvc 有哪些元件?

Spring MVC的核心元件:

  1. DispatcherServlet:中央控制器,把請求給轉發到具體的控制類
  2. Controller:具體處理請求的控制器
  3. HandlerMapping:對映處理器,負責對映中央處理器轉發給controller時的對映策略
  4. ModelAndView:服務層返回的資料和檢視層的封裝類
  5. ViewResolver:檢視解析器,解析具體的檢視
  6. Interceptors :攔截器,負責攔截我們定義的請求然後做處理工作

102. @RequestMapping 的作用是什麼?

RequestMapping是一個用來處理請求地址對映的註解,可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。

RequestMapping註解有六個屬性,下面我們把她分成三類進行說明。

value, method:

  • value:指定請求的實際地址,指定的地址可以是URI Template 模式(後面將會說明);
  • method:指定請求的method型別, GET、POST、PUT、DELETE等;

consumes,produces

  • consumes:指定處理請求的提交內容型別(Content-Type),例如application/json, text/html;
  • produces:指定返回的內容型別,僅當request請求頭中的(Accept)型別中包含該指定型別才返回;

params,headers

  • params: 指定request中必須包含某些引數值是,才讓該方法處理。
  • headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。

103. @Autowired 的作用是什麼?

第十一模組

Spring Boot / Spring Cloud

104. 什麼是 spring boot?

在Spring框架這個大家族中,產生了很多衍生框架,比如 Spring、SpringMvc框架等,Spring的核心內容在於控制反轉(IOC)和依賴注入(DI),所謂控制反轉並非是一種技術,而是一種思想,在操作方面是指在spring配置檔案中建立,依賴注入即為由spring容器為應用程式的某個物件提供資源,比如 引用物件、常量資料等。

SpringBoot是一個框架,一種全新的程式設計規範,他的產生簡化了框架的使用,所謂簡化是指簡化了Spring眾多框架中所需的大量且繁瑣的配置檔案,所以 SpringBoot是一個服務於框架的框架,服務範圍是簡化配置檔案。

105. 為什麼要用 spring boot?

  • Spring Boot使編碼變簡單
  • Spring Boot使配置變簡單
  • Spring Boot使部署變簡單
  • Spring Boot使監控變簡單
  • Spring的不足

106. spring boot 核心配置檔案是什麼?

Spring Boot提供了兩種常用的配置檔案:

  • properties檔案
  • yml檔案

107. spring boot 配置檔案有哪幾種類型?它們有什麼區別?

Spring Boot提供了兩種常用的配置檔案,分別是properties檔案和yml檔案。相對於properties檔案而言,yml檔案更年輕,也有很多的坑。可謂成也蕭何敗蕭何,yml通過空格來確定層級關係,使配置檔案結構跟清晰,但也會因為微不足道的空格而破壞了層級關係。

108. spring boot 有哪些方式可以實現熱部署?

SpringBoot熱部署實現有兩種方式:

①. 使用spring loaded

在專案中新增如下程式碼:

<build>
        <plugins>
            <plugin>
                <!-- springBoot編譯外掛-->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <dependencies>
                    <!-- spring熱部署 -->
                    <!-- 該依賴在此處下載不下來,可以放置在build標籤外部下載完成後再貼上進plugin中 -->
                    <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>springloaded</artifactId>
                        <version>1.2.6.RELEASE</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

新增完畢後需要使用mvn指令執行:

    

首先找到IDEA中的Edit configurations ,然後進行如下操作:(點選左上角的"+",然後選擇maven將出現右側面板,在紅色劃線部位輸入如圖所示指令,你可以為該指令命名(此處命名為MvnSpringBootRun))

    

 

點選儲存將會在IDEA專案執行部位出現,點選綠色箭頭執行即可

②. 使用spring-boot-devtools

在專案的pom檔案中新增依賴:

 <!--熱部署jar-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-devtools</artifactId>
 </dependency>

然後:使用 shift+ctrl+alt+"/" (IDEA中的快捷鍵) 選擇"Registry" 然後勾選 compiler.automake.allow.when.app.running

109. jpa 和 hibernate 有什麼區別?

  • JPA Java Persistence API,是Java EE 5的標準ORM介面,也是ejb3規範的一部分。
  • Hibernate,當今很流行的ORM框架,是JPA的一個實現,但是其功能是JPA的超集。
  • JPA和Hibernate之間的關係,可以簡單的理解為JPA是標準介面,Hibernate是實現。那麼Hibernate是如何實現與JPA的這種關係的呢。Hibernate主要是通過三個元件來實現的,及hibernate-annotation、hibernate-entitymanager和hibernate-core。
  • hibernate-annotation是Hibernate支援annotation方式配置的基礎,它包括了標準的JPA annotation以及Hibernate自身特殊功能的annotation。
  • hibernate-core是Hibernate的核心實現,提供了Hibernate所有的核心功能。
  • hibernate-entitymanager實現了標準的JPA,可以把它看成hibernate-core和JPA之間的介面卡,它並不直接提供ORM的功能,而是對hibernate-core進行封裝,使得Hibernate符合JPA的規範。

110. 什麼是 spring cloud?

從字面理解,Spring Cloud 就是致力於分散式系統、雲服務的框架。

Spring Cloud 是整個 Spring 家族中新的成員,是最近雲服務火爆的必然產物。

Spring Cloud 為開發人員提供了快速構建分散式系統中一些常見模式的工具,例如:

  • 配置管理
  • 服務註冊與發現
  • 斷路器
  • 智慧路由
  • 服務間呼叫
  • 負載均衡
  • 微代理
  • 控制匯流排
  • 一次性令牌
  • 全域性鎖
  • 領導選舉
  • 分散式會話
  • 叢集狀態
  • 分散式訊息
  • ……

使用 Spring Cloud 開發人員可以開箱即用的實現這些模式的服務和應用程式。這些服務可以任何環境下執行,包括分散式環境,也包括開發人員自己的膝上型電腦以及各種託管平臺。

111. spring cloud 斷路器的作用是什麼?

在Spring Cloud中使用了Hystrix 來實現斷路器的功能,斷路器可以防止一個應用程式多次試圖執行一個操作,即很可能失敗,允許它繼續而不等待故障恢復或者浪費 CPU 週期,而它確定該故障是持久的。斷路器模式也使應用程式能夠檢測故障是否已經解決,如果問題似乎已經得到糾正,應用程式可以嘗試呼叫操作。

斷路器增加了穩定性和靈活性,以一個系統,提供穩定性,而系統從故障中恢復,並儘量減少此故障的對效能的影響。它可以幫助快速地拒絕對一個操作,即很可能失敗,而不是等待操作超時(或者不返回)的請求,以保持系統的響應時間。如果斷路器提高每次改變狀態的時間的事件,該資訊可以被用來監測由斷路器保護系統的部件的健康狀況,或以提醒管理員當斷路器跳閘,以在開啟狀態。

112. spring cloud 的核心元件有哪些?

①. 服務發現——Netflix Eureka

一個RESTful服務,用來定位執行在AWS地區(Region)中的中間層服務。由兩個元件組成:Eureka伺服器和Eureka客戶端。Eureka伺服器用作服務註冊伺服器。Eureka客戶端是一個java客戶端,用來簡化與伺服器的互動、作為輪詢負載均衡器,並提供服務的故障切換支援。Netflix在其生產環境中使用的是另外的客戶端,它提供基於流量、資源利用率以及出錯狀態的加權負載均衡。

②. 客服端負載均衡——Netflix Ribbon

Ribbon,主要提供客戶側的軟體負載均衡演算法。Ribbon客戶端元件提供一系列完善的配置選項,比如連線超時、重試、重試演算法等。Ribbon內建可插拔、可定製的負載均衡元件。

③. 斷路器——Netflix Hystrix

斷路器可以防止一個應用程式多次試圖執行一個操作,即很可能失敗,允許它繼續而不等待故障恢復或者浪費 CPU 週期,而它確定該故障是持久的。斷路器模式也使應用程式能夠檢測故障是否已經解決。如果問題似乎已經得到糾正,應用程式可以嘗試呼叫操作。

④. 服務閘道器——Netflix Zuul

類似nginx,反向代理的功能,不過netflix自己增加了一些配合其他元件的特性。

⑤. 分散式配置——Spring Cloud Config

這個還是靜態的,得配合Spring Cloud Bus實現動態的配置更新。

第十二模組

十二、Hibernate

113. 為什麼要使用 hibernate?

  • 對JDBC訪問資料庫的程式碼做了封裝,大大簡化了資料訪問層繁瑣的重複性程式碼。
  • Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現。他很大程度的簡化DAO層的編碼工作
  • hibernate使用Java反射機制,而不是位元組碼增強程式來實現透明性。
  • hibernate的效能非常好,因為它是個輕量級框架。對映的靈活性很出色。它支援各種關係資料庫,從一對一到多對多的各種複雜關係。

114. 什麼是 ORM 框架?

物件-關係對映(Object-Relational Mapping,簡稱ORM),面向物件的開發方法是當今企業級應用開發環境中的主流開發方法,關係資料庫是企業級應用環境中永久存放資料的主流資料儲存系統。物件和關係資料是業務實體的兩種表現形式,業務實體在記憶體中表現為物件,在資料庫中表現為關係資料。記憶體中的物件之間存在關聯和繼承關係,而在資料庫中,關係資料無法直接表達多對多關聯和繼承關係。因此,物件-關係對映(ORM)系統一般以中介軟體的形式存在,主要實現程式物件到關係資料庫資料的對映。

115. hibernate 中如何在控制檯檢視列印的 sql 語句?

參考:blog.csdn.net/Randy_Wang_/article/details/79460306

116. hibernate 有幾種查詢方式?

  1. hql查詢

  2. sql查詢

  3. 條件查詢

hql查詢,sql查詢,條件查詢
HQL:  Hibernate Query Language. 
    面向物件的寫法:Query query = session.createQuery("from Customer where name = ?");query.setParameter(0, "老師");Query.list();


QBC:  Query By Criteria.
    (條件查詢)Criteria criteria = session.createCriteria(Customer.class);criteria.add(Restrictions.eq("name", "花姐"));List<Customer> list = criteria.list();


SQL:
	SQLQuery query = session.createSQLQuery("select * from customer");
	List<Object[]> list = query.list();
	SQLQuery query = session.createSQLQuery("select * from customer");
	query.addEntity(Customer.class);List<Customer> list = query.list();


Hql: 具體分類1、 屬性查詢 2、 引數查詢、命名引數查詢 3、 關聯查詢 4、 分頁查詢 5、 統計函式

HQL和SQL的區別
HQL是面向物件查詢操作的,SQL是結構化查詢語言 是面向資料庫表結構的

117. hibernate 實體類可以被定義為 final 嗎?

可以將Hibernate的實體類定義為final類,但這種做法並不好。因為Hibernate會使用代理模式在延遲關聯的情況下提高效能,如果你把實體類定義成final類之後,因為 Java不允許對final類進行擴充套件,所以Hibernate就無法再使用代理了,如此一來就限制了使用可以提升效能的手段。不過,如果你的持久化類實現了一個介面而且在該介面中聲明瞭所有定義於實體類中的所有public的方法輪到話,你就能夠避免出現前面所說的不利後果。

118. 在 hibernate 中使用 Integer 和 int 做對映有什麼區別?

在Hibernate中,如果將OID定義為Integer型別,那麼Hibernate就可以根據其值是否為null而判斷一個物件是否是臨時的,如果將OID定義為了int型別,還需要在hbm對映檔案中設定其unsaved-value屬性為0。

119. hibernate 是如何工作的?

hibernate工作原理:

  1. 通過Configuration config = new Configuration().configure();//讀取並解析hibernate.cfg.xml配置檔案
  2. 由hibernate.cfg.xml中的讀取並解析對映資訊
  3. 通過SessionFactory sf = config.buildSessionFactory();//建立SessionFactory
  4. Session session = sf.openSession();//開啟Sesssion
  5. Transaction tx = session.beginTransaction();//建立並啟動事務Transation
  6. persistent operate操作資料,持久化操作
  7. tx.commit();//提交事務
  8. 關閉Session
  9. 關閉SesstionFactory

120. get()和 load()的區別?

  • load() 沒有使用物件的其他屬性的時候,沒有SQL 延遲載入
  • get() 沒有使用物件的其他屬性的時候,也生成了SQL 立即載入

121. 說一下 hibernate 的快取機制?

Hibernate中的快取分為一級快取和二級快取。

一級快取就是 Session 級別的快取,在事務範圍內有效是,內建的不能被解除安裝。二級快取是 SesionFactory級別的快取,從應用啟動到應用結束有效。是可選的,預設沒有二級快取,需要手動開啟。儲存資料庫後,快取在記憶體中儲存一份,如果更新了資料庫就要同步更新。

什麼樣的資料適合存放到第二級快取中?

  • 很少被修改的資料 帖子的最後回覆時間
  • 經常被查詢的資料 電商的地點
  • 不是很重要的資料,允許出現偶爾併發的資料
  • 不會被併發訪問的資料
  • 常量資料

擴充套件:hibernate的二級快取預設是不支援分散式快取的。使用 memcahe,redis等中央快取來代替二級快取。

122. hibernate 物件有哪些狀態?

hibernate裡物件有三種狀態:

  1. Transient(瞬時):物件剛new出來,還沒設id,設了其他值。
  2. Persistent(持久):呼叫了save()、saveOrUpdate(),就變成Persistent,有id。
  3. Detached(脫管):當session close()完之後,變成Detached。

123. 在 hibernate 中 getCurrentSession 和 openSession 的區別是什麼?

openSession 從字面上可以看得出來,是開啟一個新的session物件,而且每次使用都是開啟一個新的session,假如連續使用多次,則獲得的session不是同一個物件,並且使用完需要呼叫close方法關閉session。

getCurrentSession ,從字面上可以看得出來,是獲取當前上下文一個session物件,當第一次使用此方法時,會自動產生一個session物件,並且連續使用多次時,得到的session都是同一個物件,這就是與openSession的區別之一,簡單而言,getCurrentSession 就是:如果有已經使用的,用舊的,如果沒有,建新的。

注意:在實際開發中,往往使用getCurrentSession多,因為一般是處理同一個事務(即是使用一個數據庫的情況),所以在一般情況下比較少使用openSession或者說openSession是比較老舊的一套介面了。

124. hibernate 實體類必須要有無參建構函式嗎?為什麼?

必須,因為hibernate框架會呼叫這個預設構造方法來構造例項物件,即Class類的newInstance方法,這個方法就是通過呼叫預設構造方法來建立例項物件的。

另外再提醒一點,如果你沒有提供任何構造方法,虛擬機器會自動提供預設構造方法(無參構造器),但是如果你提供了其他有引數的構造方法的話,虛擬機器就不再為你提供預設構造方法,這時必須手動把無參構造器寫在程式碼裡,否則new Xxxx()是會報錯的,所以預設的構造方法不是必須的,只在有多個構造方法時才是必須的,這裡“必須”指的是“必須手動寫出來”。

第十三模組

十三、Mybatis

125. mybatis 中 #{}和 ${}的區別是什麼?

  • #{}是預編譯處理,${}是字串替換;
  • Mybatis在處理#{}時,會將sql中的#{}替換為?號,呼叫PreparedStatement的set方法來賦值;
  • Mybatis在處理${}時,就是把${}替換成變數的值;
  • 使用#{}可以有效的防止SQL注入,提高系統安全性。

126. mybatis 有幾種分頁方式?

  1. 陣列分頁

  2. sql分頁

  3. 攔截器分頁

  4. RowBounds分頁

128. mybatis 邏輯分頁和物理分頁的區別是什麼?

  • 物理分頁速度上並不一定快於邏輯分頁,邏輯分頁速度上也並不一定快於物理分頁。
  • 物理分頁總是優於邏輯分頁:沒有必要將屬於資料庫端的壓力加諸到應用端來,就算速度上存在優勢,然而其它效能上的優點足以彌補這個缺點。

129. mybatis 是否支援延遲載入?延遲載入的原理是什麼?

Mybatis僅支援association關聯物件和collection關聯集合物件的延遲載入,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置檔案中,可以配置是否啟用延遲載入lazyLoadingEnabled=true|false。

它的原理是,使用CGLIB建立目標物件的代理物件,當呼叫目標方法時,進入攔截器方法,比如呼叫a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨傳送事先儲存好的查詢關聯B物件的sql,把B查詢上來,然後呼叫a.setB(b),於是a的物件b屬性就有值了,接著完成a.getB().getName()方法的呼叫。這就是延遲載入的基本原理。

當然了,不光是Mybatis,幾乎所有的包括Hibernate,支援延遲載入的原理都是一樣的。

130. 說一下 mybatis 的一級快取和二級快取?

一級快取: 基於 PerpetualCache 的 HashMap 本地快取,其儲存作用域為 Session,當 Session flush 或 close 之後,該 Session 中的所有 Cache 就將清空,預設開啟一級快取。

二級快取與一級快取其機制相同,預設也是採用 PerpetualCache,HashMap 儲存,不同在於其儲存作用域為 Mapper(Namespace),並且可自定義儲存源,如 Ehcache。預設不開啟二級快取,要開啟二級快取,使用二級快取屬性類需要實現Serializable序列化介面(可用來儲存物件的狀態),可在它的對映檔案中配置

對於快取資料更新機制,當某一個作用域(一級快取 Session/二級快取Namespaces)的進行了C/U/D 操作後,預設該作用域下所有 select 中的快取將被 clear。

131. mybatis 和 hibernate 的區別有哪些?

(1)Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程式設計師自己編寫Sql語句。

(2)Mybatis直接編寫原生態sql,可以嚴格控制sql執行效能,靈活度高,非常適合對關係資料模型要求不高的軟體開發,因為這類軟體需求變化頻繁,一但需求變化要求迅速輸出成果。但是靈活的前提是mybatis無法做到資料庫無關性,如果需要實現支援多種資料庫的軟體,則需要自定義多套sql對映檔案,工作量大。

(3)Hibernate物件/關係對映能力強,資料庫無關性好,對於關係模型要求高的軟體,如果用hibernate開發可以節省很多程式碼,提高效率。

132. mybatis 有哪些執行器(Executor)?

Mybatis有三種基本的執行器(Executor):

  1. SimpleExecutor:每執行一次update或select,就開啟一個Statement物件,用完立刻關閉Statement物件。
  2. ReuseExecutor:執行update或select,以sql作為key查詢Statement物件,存在就使用,不存在就建立,用完後,不關閉Statement物件,而是放置於Map內,供下一次使用。簡言之,就是重複使用Statement物件。
  3. BatchExecutor:執行update(沒有select,JDBC批處理不支援select),將所有sql都新增到批處理中(addBatch()),等待統一執行(executeBatch()),它快取了多個Statement物件,每個Statement物件都是addBatch()完畢後,等待逐一執行executeBatch()批處理。與JDBC批處理相同。

133. mybatis 分頁外掛的實現原理是什麼?

分頁外掛的基本原理是使用Mybatis提供的外掛介面,實現自定義外掛,在外掛的攔截方法內攔截待執行的sql,然後重寫sql,根據dialect方言,新增對應的物理分頁語句和物理分頁引數。

134. mybatis 如何編寫一個自定義外掛?

轉自:blog.csdn.net/qq_30051265/article/details/80266434

Mybatis自定義外掛針對Mybatis四大物件(Executor、StatementHandler 、ParameterHandler 、ResultSetHandler )進行攔截,具體攔截方式為:

  • Executor:攔截執行器的方法(log記錄)
  • StatementHandler :攔截Sql語法構建的處理
  • ParameterHandler :攔截引數的處理
  • ResultSetHandler :攔截結果集的處理

Mybatis自定義外掛必須實現Interceptor介面:

public interface Interceptor {    
    Object intercept(Invocation invocation) throws Throwable;    
    Object plugin(Object target);    
    void setProperties(Properties properties);
}

intercept方法:攔截器具體處理邏輯方法

plugin方法:根據簽名signatureMap生成動態代理物件

setProperties方法:設定Properties屬性

自定義外掛demo:

// ExamplePlugin.java
@Intercepts({@Signature(  type= Executor.class,  method = "update",  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {  
    public Object intercept(Invocation invocation) throws Throwable {  
        Object target = invocation.getTarget(); //被代理物件  
        Method method = invocation.getMethod(); //代理方法  
        Object[] args = invocation.getArgs(); //方法引數  
        // do something ...... 方法攔截前執行程式碼塊  
        Object result = invocation.proceed();  
        // do something .......方法攔截後執行程式碼塊  
        return result;  
    }  
    public Object plugin(Object target) {    
        return Plugin.wrap(target, this);  
    }  
    public void setProperties(Properties properties) {
    }
}

一個@Intercepts可以配置多個@Signature,@Signature中的引數定義如下:

  • type:表示攔截的類,這裡是Executor的實現類;
  • method:表示攔截的方法,這裡是攔截Executor的update方法;
  • args:表示方法引數。

第十四模組

十四、RabbitMQ

135. rabbitmq 的使用場景有哪些?

①. 跨系統的非同步通訊,所有需要非同步互動的地方都可以使用訊息佇列。就像我們除了打電話(同步)以外,還需要發簡訊,發電子郵件(非同步)的通訊方式。

②. 多個應用之間的耦合,由於訊息是平臺無關和語言無關的,而且語義上也不再是函式呼叫,因此更適合作為多個應用之間的鬆耦合的介面。基於訊息佇列的耦合,不需要傳送方和接收方同時線上。在企業應用整合(EAI)中,檔案傳輸,共享資料庫,訊息佇列,遠端過程呼叫都可以作為整合的方法。

③. 應用內的同步變非同步,比如訂單處理,就可以由前端應用將訂單資訊放到佇列,後端應用從佇列裡依次獲得訊息處理,高峰時的大量訂單可以積壓在佇列裡慢慢處理掉。由於同步通常意味著阻塞,而大量執行緒的阻塞會降低計算機的效能。

④. 訊息驅動的架構(EDA),系統分解為訊息佇列,和訊息製造者和訊息消費者,一個處理流程可以根據需要拆成多個階段(Stage),階段之間用佇列連線起來,前一個階段處理的結果放入佇列,後一個階段從佇列中獲取訊息繼續處理。

⑤. 應用需要更靈活的耦合方式,如釋出訂閱,比如可以指定路由規則。

⑥. 跨區域網,甚至跨城市的通訊(CDN行業),比如北京機房與廣州機房的應用程式的通訊。

136. rabbitmq 有哪些重要的角色?

RabbitMQ 中重要的角色有:生產者、消費者和代理:

  • 生產者:訊息的建立者,負責建立和推送資料到訊息伺服器;
  • 消費者:訊息的接收方,用於處理資料和確認訊息;
  • 代理:就是 RabbitMQ 本身,用於扮演“快遞”的角色,本身不生產訊息,只是扮演“快遞”的角色。

137. rabbitmq 有哪些重要的元件?

  • ConnectionFactory(連線管理器):應用程式與Rabbit之間建立連線的管理器,程式程式碼中使用。
  • Channel(通道):訊息推送使用的通道。
  • Exchange(交換器):用於接受、分配訊息。
  • Queue(佇列):用於儲存生產者的訊息。
  • RoutingKey(路由鍵):用於把生成者的資料分配到交換器上。
  • BindingKey(繫結鍵):用於把交換器的訊息繫結到佇列上。

138. rabbitmq 中 vhost 的作用是什麼?

vhost 可以理解為虛擬 broker ,即 mini-RabbitMQ server。其內部均含有獨立的 queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的許可權系統,可以做到 vhost 範圍的使用者控制。當然,從 RabbitMQ 的全域性角度,vhost 可以作為不同許可權隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。

139. rabbitmq 的訊息是怎麼傳送的?

首先客戶端必須連線到 RabbitMQ 伺服器才能釋出和消費訊息,客戶端和 rabbit server 之間會建立一個 tcp 連線,一旦 tcp 開啟並通過了認證(認證就是你傳送給 rabbit 伺服器的使用者名稱和密碼),你的客戶端和 RabbitMQ 就建立了一條 amqp 通道(channel),通道是建立在“真實” tcp 上的虛擬連線,amqp 命令都是通過通道傳送出去的,每個通道都會有一個唯一的 id,不論是釋出訊息,訂閱佇列都是通過這個通道完成的。

140. rabbitmq 怎麼保證訊息的穩定性?

  • 提供了事務的功能。
  • 通過將 channel 設定為 confirm(確認)模式。

141. rabbitmq 怎麼避免訊息丟失?

  1. 訊息持久化

  2. ACK確認機制

  3. 設定叢集映象模式

  4. 訊息補償機制

142. 要保證訊息持久化成功的條件有哪些?

  1. 宣告佇列必須設定持久化 durable 設定為 true.
  2. 訊息推送投遞模式必須設定持久化,deliveryMode 設定為 2(持久)。
  3. 訊息已經到達持久化交換器。
  4. 訊息已經到達持久化佇列。

以上四個條件都滿足才能保證訊息持久化成功。

143. rabbitmq 持久化有什麼缺點?

持久化的缺地就是降低了伺服器的吞吐量,因為使用的是磁碟而非記憶體儲存,從而降低了吞吐量。可儘量使用 ssd 硬碟來緩解吞吐量的問題。

144. rabbitmq 有幾種廣播型別?

三種廣播模式:

  1. fanout: 所有bind到此exchange的queue都可以接收訊息(純廣播,繫結到RabbitMQ的接受者都能收到訊息);
  2. direct: 通過routingKey和exchange決定的那個唯一的queue可以接收訊息;
  3. topic:所有符合routingKey(此時可以是一個表示式)的routingKey所bind的queue可以接收訊息;

145. rabbitmq 怎麼實現延遲訊息佇列?

  1. 通過訊息過期後進入死信交換器,再由交換器轉發到延遲消費佇列,實現延遲功能;
  2. 使用 RabbitMQ-delayed-message-exchange 外掛實現延遲功能。

146. rabbitmq 叢集有什麼用?

叢集主要有以下兩個用途:

  • 高可用:某個伺服器出現問題,整個 RabbitMQ 還可以繼續使用;
  • 高容量:叢集可以承載更多的訊息量。

147. rabbitmq 節點的型別有哪些?

  • 磁碟節點:訊息會儲存到磁碟。
  • 記憶體節點:訊息都儲存在記憶體中,重啟伺服器訊息丟失,效能高於磁碟型別。

148. rabbitmq 叢集搭建需要注意哪些問題?

  • 各節點之間使用“--link”連線,此屬性不能忽略。
  • 各節點使用的 erlang cookie 值必須相同,此值相當於“祕鑰”的功能,用於各節點的認證。
  • 整個叢集中必須包含一個磁碟節點。

149. rabbitmq 每個節點是其他節點的完整拷貝嗎?為什麼?

不是,原因有以下兩個:

  1. 儲存空間的考慮:如果每個節點都擁有所有佇列的完全拷貝,這樣新增節點不但沒有新增儲存空間,反而增加了更多的冗餘資料;
  2. 效能的考慮:如果每條訊息都需要完整拷貝到每一個叢集節點,那新增節點並沒有提升處理訊息的能力,最多是保持和單節點相同的效能甚至是更糟。

150. rabbitmq 叢集中唯一一個磁碟節點崩潰了會發生什麼情況?

如果唯一磁碟的磁碟節點崩潰了,不能進行以下操作:

  • 不能建立佇列
  • 不能建立交換器
  • 不能建立繫結
  • 不能新增使用者
  • 不能更改許可權
  • 不能新增和刪除叢集節點

唯一磁碟節點崩潰了,叢集是可以保持執行的,但你不能更改任何東西。

151. rabbitmq 對叢集節點停止順序有要求嗎?

RabbitMQ 對叢集的停止的順序是有要求的,應該先關閉記憶體節點,最後再關閉磁碟節點。如果順序恰好相反的話,可能會造成訊息的丟失。

第十五模組

十五、Kafka

152. kafka 可以脫離 zookeeper 單獨使用嗎?為什麼?

kafka 不能脫離 zookeeper 單獨使用,因為 kafka 使用 zookeeper 管理和協調 kafka 的節點伺服器。

153. kafka 有幾種資料保留的策略?

kafka 有兩種資料儲存策略:按照過期時間保留和按照儲存的訊息大小保留。

154. kafka 同時設定了 7 天和 10G 清除資料,到第五天的時候訊息達到了 10G,這個時候 kafka 將如何處理?

這個時候 kafka 會執行資料清除工作,時間和大小不論那個滿足條件,都會清空資料。

155. 什麼情況會導致 kafka 執行變慢?

  • cpu 效能瓶頸
  • 磁碟讀寫瓶頸
  • 網路瓶頸

156. 使用 kafka 叢集需要注意什麼?

  • 叢集的數量不是越多越好,最好不要超過 7 個,因為節點越多,訊息複製需要的時間就越長,整個群組的吞吐量就越低。
  • 叢集數量最好是單數,因為超過一半故障叢集就不能用了,設定為單數容錯率更高。

第十六模組

十六、Zookeeper

157. zookeeper 是什麼?

zookeeper 是一個分散式的,開放原始碼的分散式應用程式協調服務,是 google chubby 的開源實現,是 hadoop 和 hbase 的重要元件。它是一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、域名服務、分散式同步、組服務等。

158. zookeeper 都有哪些功能?

  • 叢集管理:監控節點存活狀態、執行請求等。
  • 主節點選舉:主節點掛掉了之後可以從備用的節點開始新一輪選主,主節點選舉說的就是這個選舉的過程,使用 zookeeper 可以協助完成這個過程。
  • 分散式鎖:zookeeper 提供兩種鎖:獨佔鎖、共享鎖。獨佔鎖即一次只能有一個執行緒使用資源,共享鎖是讀鎖共享,讀寫互斥,即可以有多線執行緒同時讀同一個資源,如果要使用寫鎖也只能有一個執行緒使用。zookeeper可以對分散式鎖進行控制。
  • 命名服務:在分散式系統中,通過使用命名服務,客戶端應用能夠根據指定名字來獲取資源或服務的地址,提供者等資訊。

159. zookeeper 有幾種部署模式?

zookeeper 有三種部署模式:

  • 單機部署:一臺叢集上執行;
  • 叢集部署:多臺叢集執行;
  • 偽叢集部署:一臺叢集啟動多個 zookeeper 例項執行。

160. zookeeper 怎麼保證主從節點的狀態同步?

zookeeper 的核心是原子廣播,這個機制保證了各個 server 之間的同步。實現這個機制的協議叫做 zab 協議。 zab 協議有兩種模式,分別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰後,zab 就進入了恢復模式,當領導者被選舉出來,且大多數 server 完成了和 leader 的狀態同步以後,恢復模式就結束了。狀態同步保證了 leader 和 server 具有相同的系統狀態。

161. 叢集中為什麼要有主節點?

在分散式環境中,有些業務邏輯只需要叢集中的某一臺機器進行執行,其他的機器可以共享這個結果,這樣可以大大減少重複計算,提高效能,所以就需要主節點。

162. 叢集中有 3 臺伺服器,其中一個節點宕機,這個時候 zookeeper 還可以使用嗎?

可以繼續使用,單數伺服器只要沒超過一半的伺服器宕機就可以繼續使用。

163. 說一下 zookeeper 的通知機制?

客戶端端會對某個 znode 建立一個 watcher 事件,當該 znode 發生變化時,這些客戶端會收到 zookeeper 的通知,然後客戶端可以根據 znode 變化來做出業務上的改變。

第十七模組

十七、MySql

164. 資料庫的三正規化是什麼?

  • 第一正規化:強調的是列的原子性,即資料庫表的每一列都是不可分割的原子資料項。
  • 第二正規化:要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性。
  • 第三正規化:任何非主屬性不依賴於其它非主屬性。

165. 一張自增表裡面總共有 7 條資料,刪除了最後 2 條資料,重啟 mysql 資料庫,又插入了一條資料,此時 id 是幾?

  • 表型別如果是 MyISAM ,那 id 就是 8。
  • 表型別如果是 InnoDB,那 id 就是 6。

InnoDB 表只會把自增主鍵的最大 id 記錄在記憶體中,所以重啟之後會導致最大 id 丟失。

166. 如何獲取當前資料庫版本?

使用 select version() 獲取當前 MySQL 資料庫版本。

167. 說一下 ACID 是什麼?

  • Atomicity(原子性):一個事務(transaction)中的所有操作,或者全部完成,或者全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。即,事務不可分割、不可約簡。
  • Consistency(一致性):在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設約束、觸發器、級聯回滾等。
  • Isolation(隔離性):資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致資料的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和序列化(Serializable)。
  • Durability(永續性):事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。

168. char 和 varchar 的區別是什麼?

char(n) :固定長度型別,比如訂閱 char(10),當你輸入"abc"三個字元的時候,它們佔的空間還是 10 個位元組,其他 7 個是空位元組。

chat 優點:效率高;缺點:佔用空間;適用場景:儲存密碼的 md5 值,固定長度的,使用 char 非常合適。

varchar(n) :可變長度,儲存的值是每個值佔用的位元組再加上一個用來記錄其長度的位元組的長度。

所以,從空間上考慮 varcahr 比較合適;從效率上考慮 char 比較合適,二者使用需要權衡。

169. float 和 double 的區別是什麼?

  • float 最多可以儲存 8 位的十進位制數,並在記憶體中佔 4 位元組。
  • double 最可可以儲存 16 位的十進位制數,並在記憶體中佔 8 位元組。

170. mysql 的內連線、左連線、右連線有什麼區別?

內連線關鍵字:inner join;左連線:left join;右連線:right join。

內連線是把匹配的關聯資料顯示出來;左連線是左邊的表全部顯示出來,右邊的表顯示出符合條件的資料;右連線正好相反。

171. mysql 索引是怎麼實現的?

索引是滿足某種特定查詢演算法的資料結構,而這些資料結構會以某種方式指向資料,從而實現高效查詢資料。

具體來說 MySQL 中的索引,不同的資料引擎實現有所不同,但目前主流的資料庫引擎的索引都是 B+ 樹實現的,B+ 樹的搜尋效率,可以到達二分法的效能,找到資料區域之後就找到了完整的資料結構了,所有索引的效能也是更好的。

172. 怎麼驗證 mysql 的索引是否滿足需求?

使用 explain 檢視 SQL 是如何執行查詢語句的,從而分析你的索引是否滿足需求。

explain 語法:explain select * from table where type=1。

173. 說一下資料庫的事務隔離?

MySQL 的事務隔離是在 MySQL. ini 配置檔案裡新增的,在檔案的最後新增:transaction-isolation = REPEATABLE-READ

可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。

  • READ-UNCOMMITTED:未提交讀,最低隔離級別、事務未提交前,就可被其他事務讀取(會出現幻讀、髒讀、不可重複讀)。
  • READ-COMMITTED:提交讀,一個事務提交後才能被其他事務讀取到(會造成幻讀、不可重複讀)。
  • REPEATABLE-READ:可重複讀,預設級別,保證多次讀取同一個資料時,其值都和事務開始時候的內容是一致,禁止讀取到別的事務未提交的資料(會造成幻讀)。
  • SERIALIZABLE:序列化,代價最高最可靠的隔離級別,該隔離級別能防止髒讀、不可重複讀、幻讀。

髒讀 :表示一個事務能夠讀取另一個事務中還未提交的資料。比如,某個事務嘗試插入記錄 A,此時該事務還未提交,然後另一個事務嘗試讀取到了記錄 A。

不可重複讀 :是指在一個事務內,多次讀同一資料。

幻讀 :指同一個事務內多次查詢返回的結果集不一樣。比如同一個事務 A 第一次查詢時候有 n 條記錄,但是第二次同等條件下查詢卻有 n+1 條記錄,這就好像產生了幻覺。發生幻讀的原因也是另外一個事務新增或者刪除或者修改了第一個事務結果集裡面的資料,同一個記錄的資料內容被修改了,所有資料行的記錄就變多或者變少了。

174. 說一下 mysql 常用的引擎?

InnoDB 引擎:InnoDB 引擎提供了對資料庫 acid 事務的支援,並且還提供了行級鎖和外來鍵的約束,它的設計的目標就是處理大資料容量的資料庫系統。MySQL 執行的時候,InnoDB 會在記憶體中建立緩衝池,用於緩衝資料和索引。但是該引擎是不支援全文搜尋,同時啟動也比較的慢,它是不會儲存表的行數的,所以當進行 select count(*) from table 指令的時候,需要進行掃描全表。由於鎖的粒度小,寫操作是不會鎖定全表的,所以在併發度較高的場景下使用會提升效率的。

MyIASM 引擎:MySQL 的預設引擎,但不提供事務的支援,也不支援行級鎖和外來鍵。因此當執行插入和更新語句時,即執行寫操作的時候需要鎖定這個表,所以會導致效率會降低。不過和 InnoDB 不同的是,MyIASM 引擎是儲存了表的行數,於是當進行 select count(*) from table 語句時,可以直接的讀取已經儲存的值而不需要進行掃描全表。所以,如果表的讀操作遠遠多於寫操作時,並且不需要事務的支援的,可以將 MyIASM 作為資料庫引擎的首選。

175. 說一下 mysql 的行鎖和表鎖?

MyISAM 只支援表鎖,InnoDB 支援表鎖和行鎖,預設為行鎖。

  • 表級鎖:開銷小,加鎖快,不會出現死鎖。鎖定粒度大,發生鎖衝突的概率最高,併發量最低。
  • 行級鎖:開銷大,加鎖慢,會出現死鎖。鎖力度小,發生鎖衝突的概率小,併發度最高。

176. 說一下樂觀鎖和悲觀鎖?

  • 樂觀鎖:每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在提交更新的時候會判斷一下在此期間別人有沒有去更新這個資料。
  • 悲觀鎖:每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會阻止,直到這個鎖被釋放。

資料庫的樂觀鎖需要自己實現,在表裡面新增一個 version 欄位,每次修改成功值加 1,這樣每次修改的時候先對比一下,自己擁有的 version 和資料庫現在的 version 是否一致,如果不一致就不修改,這樣就實現了樂觀鎖。

177. mysql 問題排查都有哪些手段?

  • 使用 show processlist 命令檢視當前所有連線資訊。
  • 使用 explain 命令查詢 SQL 語句執行計劃。
  • 開啟慢查詢日誌,檢視慢查詢的 SQL。

178. 如何做 mysql 的效能優化?

  • 為搜尋欄位建立索引。
  • 避免使用 select *,列出需要查詢的欄位。
  • 垂直分割分表。
  • 選擇正確的儲存引擎。

第十八模組

十八、Redis

179. redis 是什麼?都有哪些使用場景?

Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。

Redis 使用場景:

  • 資料高併發的讀寫
  • 海量資料的讀寫
  • 對擴充套件性要求高的資料

180. redis 有哪些功能?

  • 資料快取功能
  • 分散式鎖的功能
  • 支援資料持久化
  • 支援事務
  • 支援訊息佇列

181. redis 和 memecache 有什麼區別?

  • memcached所有的值均是簡單的字串,redis作為其替代者,支援更為豐富的資料型別
  • redis的速度比memcached快很多
  • redis可以持久化其資料

182. redis 為什麼是單執行緒的?

因為 cpu 不是 Redis 的瓶頸,Redis 的瓶頸最有可能是機器記憶體或者網路頻寬。既然單執行緒容易實現,而且 cpu 又不會成為瓶頸,那就順理成章地採用單執行緒的方案了。

關於 Redis 的效能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求。

而且單執行緒並不代表就慢 nginx 和 nodejs 也都是高效能單執行緒的代表。

183. 什麼是快取穿透?怎麼解決?

快取穿透:指查詢一個一定不存在的資料,由於快取是不命中時需要從資料庫查詢,查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到資料庫去查詢,造成快取穿透。

解決方案:最簡單粗暴的方法如果一個查詢返回的資料為空(不管是資料不存在,還是系統故障),我們就把這個空結果進行快取,但它的過期時間會很短,最長不超過五分鐘。

184. redis 支援的資料型別有哪些?

string、list、hash、set、zset。

185. redis 支援的 java 客戶端都有哪些?

Redisson、Jedis、lettuce等等,官方推薦使用Redisson。

186. jedis 和 redisson 有哪些區別?

Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支援。

Redisson實現了分散式和可擴充套件的Java資料結構,和Jedis相比,功能較為簡單,不支援字串操作,不支援排序、事務、管道、分割槽等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。

187. 怎麼保證快取和資料庫資料的一致性?

  • 合理設定快取的過期時間。
  • 新增、更改、刪除資料庫操作時同步更新 Redis,可以使用事物機制來保證資料的一致性。

188. redis 持久化有幾種方式?

Redis 的持久化有兩種方式,或者說有兩種策略:

  • RDB(Redis Database):指定的時間間隔能對你的資料進行快照儲存。
  • AOF(Append Only File):每一個收到的寫命令都通過write函式追加到檔案中。

189. redis 怎麼實現分散式鎖?

Redis 分散式鎖其實就是在系統裡面佔一個“坑”,其他程式也要佔“坑”的時候,佔用成功了就可以繼續執行,失敗了就只能放棄或稍後重試。

佔坑一般使用 setnx(set if not exists)指令,只允許被一個程式佔有,使用完呼叫 del 釋放鎖。

190. redis 分散式鎖有什麼缺陷?

Redis 分散式鎖不能解決超時的問題,分散式鎖有一個超時時間,程式的執行如果超出了鎖的超時時間就會出現問題。

191. redis 如何做記憶體優化?

儘可能使用散列表(hashes),散列表(是說散列表裡面儲存的數少)使用的記憶體非常小,所以你應該儘可能的將你的資料模型抽象到一個散列表裡面。

比如你的web系統中有一個使用者物件,不要為這個使用者的名稱,姓氏,郵箱,密碼設定單獨的key,而是應該把這個使用者的所有資訊儲存到一張散列表裡面。

192. redis 淘汰策略有哪些?

  • volatile-lru:從已設定過期時間的資料集(server. db[i]. expires)中挑選最近最少使用的資料淘汰。
  • volatile-ttl:從已設定過期時間的資料集(server. db[i]. expires)中挑選將要過期的資料淘汰。
  • volatile-random:從已設定過期時間的資料集(server. db[i]. expires)中任意選擇資料淘汰。
  • allkeys-lru:從資料集(server. db[i]. dict)中挑選最近最少使用的資料淘汰。
  • allkeys-random:從資料集(server. db[i]. dict)中任意選擇資料淘汰。
  • no-enviction(驅逐):禁止驅逐資料。

193. redis 常見的效能問題有哪些?該如何解決?

  • 主伺服器寫記憶體快照,會阻塞主執行緒的工作,當快照比較大時對效能影響是非常大的,會間斷性暫停服務,所以主伺服器最好不要寫記憶體快照。
  • Redis 主從複製的效能問題,為了主從複製的速度和連線的穩定性,主從庫最好在同一個區域網內。

第十九模組

十九、JVM

194. 說一下 jvm 的主要組成部分?及其作用?

  • 類載入器(ClassLoader)
  • 執行時資料區(Runtime Data Area)
  • 執行引擎(Execution Engine)
  • 本地庫介面(Native Interface)

元件的作用: 首先通過類載入器(ClassLoader)會把 Java 程式碼轉換成位元組碼,執行時資料區(Runtime Data Area)再把位元組碼載入到記憶體中,而位元組碼檔案只是 JVM 的一套指令集規範,並不能直接交個底層作業系統去執行,因此需要特定的命令解析器執行引擎(Execution Engine),將位元組碼翻譯成底層系統指令,再交由 CPU 去執行,而這個過程中需要呼叫其他語言的本地庫介面(Native Interface)來實現整個程式的功能。

195. 說一下 jvm 執行時資料區?

  • 程式計數器
  • 虛擬機器棧
  • 本地方法棧
  • 方法區

有的區域隨著虛擬機器程序的啟動而存在,有的區域則依賴使用者程序的啟動和結束而建立和銷燬。

196. 說一下堆疊的區別?

  1. 棧記憶體儲存的是區域性變數而堆記憶體儲存的是實體;

  2. 棧記憶體的更新速度要快於堆記憶體,因為區域性變數的生命週期很短;

  3. 棧記憶體存放的變數生命週期一旦結束就會被釋放,而堆記憶體存放的實體會被垃圾回收機制不定時的回收。

197. 佇列和棧是什麼?有什麼區別?

  • 佇列和棧都是被用來預儲存資料的。
  • 佇列允許先進先出檢索元素,但也有例外的情況,Deque 介面允許從兩端檢索元素。
  • 棧和佇列很相似,但它執行對元素進行後進先出進行檢索。

198. 什麼是雙親委派模型?

在介紹雙親委派模型之前先說下類載入器。對於任意一個類,都需要由載入它的類載入器和這個類本身一同確立在 JVM 中的唯一性,每一個類載入器,都有一個獨立的類名稱空間。類載入器就是根據指定全限定名稱將 class 檔案載入到 JVM 記憶體,然後再轉化為 class 物件。

類載入器分類:

  • 啟動類載入器(Bootstrap ClassLoader),是虛擬機器自身的一部分,用來載入Java_HOME/lib/目錄中的,或者被 -Xbootclasspath 引數所指定的路徑中並且被虛擬機器識別的類庫;
  • 其他類載入器:
  • 擴充套件類載入器(Extension ClassLoader):負責載入<java_home style="box-sizing: border-box; -webkit-tap-highlight-color: transparent; text-size-adjust: none; -webkit-font-smoothing: antialiased; outline: 0px !important;">\lib\ext目錄或Java. ext. dirs系統變數指定的路徑中的所有類庫;</java_home>
  • 應用程式類載入器(Application ClassLoader)。負責載入使用者類路徑(classpath)上的指定類庫,我們可以直接使用這個類載入器。一般情況,如果我們沒有自定義類載入器預設就是用這個載入器。

雙親委派模型:如果一個類載入器收到了類載入的請求,它首先不會自己去載入這個類,而是把這個請求委派給父類載入器去完成,每一層的類載入器都是如此,這樣所有的載入請求都會被傳送到頂層的啟動類載入器中,只有當父載入無法完成載入請求(它的搜尋範圍中沒找到所需的類)時,子載入器才會嘗試去載入類。

199. 說一下類載入的執行過程?

類載入分為以下 5 個步驟:

  1. 載入:根據查詢路徑找到相應的 class 檔案然後匯入;
  2. 檢查:檢查載入的 class 檔案的正確性;
  3. 準備:給類中的靜態變數分配記憶體空間;
  4. 解析:虛擬機器將常量池中的符號引用替換成直接引用的過程。符號引用就理解為一個標示,而在直接引用直接指向記憶體中的地址;
  5. 初始化:對靜態變數和靜態程式碼塊執行初始化工作。

200. 怎麼判斷物件是否可以被回收?

一般有兩種方法來判斷:

  • 引用計數器:為每個物件建立一個引用計數,有物件引用時計數器 +1,引用被釋放時計數 -1,當計數器為 0 時就可以被回收。它有一個缺點不能解決迴圈引用的問題;
  • 可達性分析:從 GC Roots 開始向下搜尋,搜尋所走過的路徑稱為引用鏈。當一個物件到 GC Roots 沒有任何引用鏈相連時,則證明此物件是可以被回收的。

201. java 中都有哪些引用型別?

  • 強引用
  • 軟引用
  • 弱引用
  • 虛引用(幽靈引用/幻影引用)

202. 說一下 jvm 有哪些垃圾回收演算法?

  • 標記-清除演算法
  • 標記-整理演算法
  • 複製演算法
  • 分代演算法

203. 說一下 jvm 有哪些垃圾回收器?

  • Serial:最早的單執行緒序列垃圾回收器。
  • Serial Old:Serial 垃圾回收器的老年版本,同樣也是單執行緒的,可以作為 CMS 垃圾回收器的備選預案。
  • ParNew:是 Serial 的多執行緒版本。
  • Parallel 和 ParNew 收集器類似是多執行緒的,但 Parallel 是吞吐量優先的收集器,可以犧牲等待時間換取系統的吞吐量。
  • Parallel Old 是 Parallel 老生代版本,Parallel 使用的是複製的記憶體回收演算法,Parallel Old 使用的是標記-整理的記憶體回收演算法。
  • CMS:一種以獲得最短停頓時間為目標的收集器,非常適用 B/S 系統。
  • G1:一種兼顧吞吐量和停頓時間的 GC 實現,是 JDK 9 以後的預設 GC 選項。

204. 詳細介紹一下 CMS 垃圾回收器?

CMS 是英文 Concurrent Mark-Sweep 的簡稱,是以犧牲吞吐量為代價來獲得最短回收停頓時間的垃圾回收器。對於要求伺服器響應速度的應用上,這種垃圾回收器非常適合。在啟動 JVM 的引數加上“-XX:+UseConcMarkSweepGC”來指定使用 CMS 垃圾回收器。

CMS 使用的是標記-清除的演算法實現的,所以在 gc 的時候回產生大量的記憶體碎片,當剩餘記憶體不能滿足程式執行要求時,系統將會出現 Concurrent Mode Failure,臨時 CMS 會採用 Serial Old 回收器進行垃圾清除,此時的效能將會被降低。

205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什麼區別?

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G1

新生代垃圾回收器一般採用的是複製演算法,複製演算法的優點是效率高,缺點是記憶體利用率低;老年代回收器一般採用的是標記-整理的演算法進行垃圾回收。

206. 簡述分代垃圾回收器是怎麼工作的?

分代回收器有兩個分割槽:老生代和新生代,新生代預設的空間佔比總空間的 1/3,老生代的預設佔比是 2/3。

新生代使用的是複製演算法,新生代裡有 3 個分割槽:Eden、To Survivor、From Survivor,它們的預設佔比是 8:1:1,它的執行流程如下:

  • 把 Eden + From Survivor 存活的物件放入 To Survivor 區;
  • 清空 Eden 和 From Survivor 分割槽;
  • From Survivor 和 To Survivor 分割槽交換,From Survivor 變 To Survivor,To Survivor 變 From Survivor。

每次在 From Survivor 到 To Survivor 移動時都存活的物件,年齡就 +1,當年齡到達 15(預設配置是 15)時,升級為老生代。大物件也會直接進入老生代。

老生代當空間佔用到達某個值之後就會觸發全域性垃圾收回,一般使用標記整理的執行演算法。以上這些迴圈往復就構成了整個分代垃圾回收的整體執行流程。

207. 說一下 jvm 調優的工具?

JDK 自帶了很多監控工具,都位於 JDK 的 bin 目錄下,其中最常用的是 jconsole 和 jvisualvm 這兩款檢視監控工具。

  • jconsole:用於對 JVM 中的記憶體、執行緒和類等進行監控;
  • jvisualvm:JDK 自帶的全能分析工具,可以分析:記憶體快照、執行緒快照、程式死鎖、監控記憶體的變化、gc 變化等。

208. 常用的 jvm 調優的引數都有哪些?

  • -Xms2g:初始化推大小為 2g;
  • -Xmx2g:堆最大記憶體為 2g;
  • -XX:NewRatio=4:設定年輕的和老年代的記憶體比例為 1:4;
  • -XX:SurvivorRatio=8:設定新生代 Eden 和 Survivor 比例為 8:2;
  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器組合;
  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器組合;
  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器組合;
  • -XX:+PrintGC:開啟列印 gc 資訊;
  • -XX:+PrintGCDetails:列印 gc 詳細資訊。