2019最新整理208道JAVA面試題(附答案)續

十一. Spring Boot/Spring Cloud模組

104。什麼是 spring boot?

spring boot 是為 spring 服務的,是用來簡化新 spring 應用的初始搭建以及開發過程的。

105。為什麼要用 spring boot?

配置簡單

獨立執行

自動裝配

無程式碼生成和 xml 配置

提供應用監控

易上手

提升開發效率

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

spring boot 核心的兩個配置檔案:

bootstrap (。 yml 或者 。 properties):boostrap 由父 ApplicationContext 載入的,比 applicaton 優先載入,且 boostrap 裡面的屬性不能被覆蓋;

application (。 yml 或者 。 properties):用於 spring boot 專案的自動化配置。

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

配置檔案有 。 properties 格式和 。 yml 格式,它們主要的區別是書法風格不同。

properties 配置如下:

spring。 RabbitMQ。 port=5672

yml 配置如下:

spring:

RabbitMQ:

port: 5672

yml 格式不支援 @PropertySource 註解匯入。

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

使用 devtools 啟動熱部署,新增 devtools 庫,在配置檔案中把 spring。 devtools。 restart。 enabled 設定為 true;

使用 Intellij Idea 編輯器,勾上自動編譯或手動重新編譯。

109。jpa 和 hibernate 有什麼區別?

jpa 全稱 Java Persistence API,是 Java 持久化介面規範,hibernate 屬於 jpa 的具體實現。

110。什麼是 spring cloud?

spring cloud 是一系列框架的有序集合。它利用 spring boot 的開發便利性巧妙地簡化了分散式系統基礎設施的開發,如服務發現註冊、配置中心、訊息匯流排、負載均衡、斷路器、資料監控等,都可以用 spring boot 的開發風格做到一鍵啟動和部署。

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

在分散式架構中,斷路器模式的作用也是類似的,當某個服務單元發生故障(類似用電器發生短路)之後,透過斷路器的故障監控(類似熔斷保險絲),向呼叫方返回一個錯誤響應,而不是長時間的等待。這樣就不會使得執行緒因呼叫故障服務被長時間佔用不釋放,避免了故障在分散式系統中的蔓延。

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

Eureka:服務註冊於發現。

Feign:基於動態代理機制,根據註解和選擇的機器,拼接請求 url 地址,發起請求。

Ribbon:實現負載均衡,從一個服務的多臺機器中選擇一臺。

Hystrix:提供執行緒池,不同的服務走不同的執行緒池,實現了不同服務呼叫的隔離,避免了服務雪崩的問題。

Zuul:閘道器管理,由 Zuul 閘道器轉發請求給對應的服務。

···

====================================================================

十二。 Hibernate模組

113。為什麼要使用 hibernate?

hibernate 是對 jdbc 的封裝,大大簡化了資料訪問層的繁瑣的重複性程式碼。

hibernate 是一個優秀的 ORM 實現,很多程度上簡化了 DAO 層的編碼功能。

可以很方便的進行資料庫的移植工作。

提供了快取機制,是程式執行更改的高效。

114。什麼是 ORM 框架?

ORM(Object Relation Mapping)物件關係對映,是把資料庫中的關係資料對映成為程式中的物件。

使用 ORM 的優點:提高了開發效率降低了開發成本、開發更簡單更物件化、可移植更強。

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

在 Config 裡面把 hibernate。 show_SQL 設定為 true 就可以。但不建議開啟,開啟之後會降低程式的執行效率。

116。hibernate 有幾種查詢方式?

三種:hql、原生 SQL、條件查詢 Criteria。

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

實體類可以定義為 final 類,但這樣的話就不能使用 hibernate 代理模式下的延遲關聯提供效能了,所以不建議定義實體類為 final。

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

Integer 型別為物件,它的值允許為 null,而 int 屬於基礎資料型別,值不能為 null。

119。hibernate 是如何工作的?

讀取並解析配置檔案。

讀取並解析對映檔案,建立 SessionFactory。

開啟 Session。

建立事務。

進行持久化操作。

提交事務。

關閉 Session。

關閉 SessionFactory。

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

資料查詢時,沒有 OID 指定的物件,get() 返回 null;load() 返回一個代理物件。

load()支援延遲載入;get() 不支援延遲載入。

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

hibernate 常用的快取有一級快取和二級快取:

一級快取:也叫 Session 快取,只在 Session 作用範圍內有效,不需要使用者干涉,由 hibernate 自身維護,可以透過:evict(object)清除 object 的快取;clear()清除一級快取中的所有快取;flush()刷出快取;

二級快取:應用級別的快取,在所有 Session 中都有效,支援配置第三方的快取,如:EhCache。

122。hibernate 物件有哪些狀態?

臨時/瞬時狀態:直接 new 出來的物件,該物件還沒被持久化(沒儲存在資料庫中),不受 Session 管理。

持久化狀態:當呼叫 Session 的 save/saveOrupdate/get/load/list 等方法的時候,物件就是持久化狀態。

遊離狀態:Session 關閉之後物件就是遊離狀態。

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

getCurrentSession 會綁定當前執行緒,而 openSession 則不會。

getCurrentSession 事務是 Spring 控制的,並且不需要手動關閉,而 openSession 需要我們自己手動開啟和提交事務。

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

hibernate 中每個實體類必須提供一個無參建構函式,因為 hibernate 框架要使用 reflection api,透過呼叫 ClassnewInstance() 來建立實體類的例項,如果沒有無參的建構函式就會丟擲異常。

···

====================================================================

十三。 MyBatis模組

125。MyBatis 中 #{}和 ${}的區別是什麼?

#{}是預編譯處理,${}是字元替換。在使用 #{}時,MyBatis 會將 SQL 中的 #{}替換成“?”,配合 PreparedStatement 的 set 方法賦值,這樣可以有效的防止 SQL 注入,保證程式的執行安全。

126。MyBatis 有幾種分頁方式?

分頁方式:邏輯分頁和物理分頁。

邏輯分頁:使用 MyBatis 自帶的 RowBounds 進行分頁,它是一次性查詢很多資料,然後在資料中再進行檢索。

物理分頁:自己手寫 SQL 分頁或使用分頁外掛 PageHelper,去資料庫查詢指定條數的分頁資料的形式。

127。RowBounds 是一次性查詢全部結果嗎?為什麼?

RowBounds 表面是在“所有”資料中檢索資料,其實並非是一次性查詢出所有資料,因為 MyBatis 是對 jdbc 的封裝,在 jdbc 驅動中有一個 Fetch Size 的配置,它規定了每次最多從資料庫查詢多少條資料,假如你要查詢更多資料,它會在你執行 next()的時候,去查詢更多的資料。就好比你去自動取款機取 10000 元,但取款機每次最多能取 2500 元,所以你要取 4 次才能把錢取完。只是對於 jdbc 來說,當你呼叫 next()的時候會自動幫你完成查詢工作。這樣做的好處可以有效的防止記憶體溢位。

Fetch Size 官方相關文件:http://t。 cn/EfSE2g3

128。MyBatis 邏輯分頁和物理分頁的區別是什麼?

邏輯分頁是一次性查詢很多資料,然後再在結果中檢索分頁的資料。這樣做弊端是需要消耗大量的記憶體、有記憶體溢位的風險、對資料庫壓力較大。

物理分頁是從資料庫查詢指定條數的資料,彌補了一次性全部查出的所有資料的種種缺點,比如需要大量的記憶體,對資料庫查詢壓力較大等問題。

129。MyBatis 是否支援延遲載入?延遲載入的原理是什麼?

MyBatis 支援延遲載入,設定 lazyLoadingEnabled=true 即可。

延遲載入的原理的是呼叫的時候觸發載入,而不是在初始化的時候就載入資訊。比如呼叫 a。 getB()。 getName(),這個時候發現 a。 getB() 的值為 null,此時會單獨觸發事先儲存好的關聯 B 物件的 SQL,先查詢出來 B,然後再呼叫 a。 setB(b),而這時候再呼叫 a。 getB()。 getName() 就有值了,這就是延遲載入的基本原理。

130。說一下 MyBatis 的一級快取和二級快取?

一級快取:基於 PerpetualCache 的 HashMap 本地快取,它的宣告週期是和 SQLSession 一致的,有多個 SQLSession 或者分散式的環境中資料庫操作,可能會出現髒資料。當 Session flush 或 close 之後,該 Session 中的所有 Cache 就將清空,預設一級快取是開啟的。

二級快取:也是基於 PerpetualCache 的 HashMap 本地快取,不同在於其儲存作用域為 Mapper 級別的,如果多個SQLSession之間需要共享快取,則需要使用到二級快取,並且二級快取可自定義儲存源,如 Ehcache。預設不開啟二級快取,要開啟二級快取,使用二級快取屬性類需要實現 Serializable 序列化介面(可用來儲存物件的狀態)。

開啟二級快取資料查詢流程:二級快取 -> 一級快取 -> 資料庫。

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

131。MyBatis 和 hibernate 的區別有哪些?

靈活性:MyBatis 更加靈活,自己可以寫 SQL 語句,使用起來比較方便。

可移植性:MyBatis 有很多自己寫的 SQL,因為每個資料庫的 SQL 可以不相同,所以可移植性比較差。

學習和使用門檻:MyBatis 入門比較簡單,使用門檻也更低。

二級快取:hibernate 擁有更好的二級快取,它的二級快取可以自行更換為第三方的二級快取。

132。MyBatis 有哪些執行器(Executor)?

MyBatis 有三種基本的Executor執行器:

SimpleExecutor:每執行一次 update 或 select 就開啟一個 Statement 物件,用完立刻關閉 Statement 物件;

ReuseExecutor:執行 update 或 select,以 SQL 作為 key 查詢 Statement 物件,存在就使用,不存在就建立,用完後不關閉 Statement 物件,而是放置於 Map 內供下一次使用。簡言之,就是重複使用 Statement 物件;

BatchExecutor:執行 update(沒有 select,jdbc 批處理不支援 select),將所有 SQL 都新增到批處理中(addBatch()),等待統一執行(executeBatch()),它快取了多個 Statement 物件,每個 Statement 物件都是 addBatch()完畢後,等待逐一執行 executeBatch()批處理,與 jdbc 批處理相同。

133。MyBatis 分頁外掛的實現原理是什麼?

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

134。MyBatis 如何編寫一個自定義外掛?

自定義外掛實現原理:

MyBatis 自定義外掛針對 MyBatis 四大物件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)進行攔截:

Executor:攔截內部執行器,它負責呼叫 StatementHandler 操作資料庫,並把結果集透過 ResultSetHandler 進行自動對映,另外它還處理了二級快取的操作;

StatementHandler:攔截 SQL 語法構建的處理,它是 MyBatis 直接和資料庫執行 SQL 指令碼的物件,另外它也實現了 MyBatis 的一級快取;

ParameterHandler:攔截引數的處理;

ResultSetHandler:攔截結果集的處理。

自定義外掛實現關鍵:

MyBatis 外掛要實現 Interceptor 介面,介面包含的方法,如下:

public interface Interceptor {

Object intercept(Invocation invocation) throws Throwable;

Object plugin(Object target);

void setProperties(Properties properties);

}

setProperties 方法是在 MyBatis 進行配置外掛的時候可以配置自定義相關屬性,即:介面實現物件的引數配置;

plugin 方法是外掛用於封裝目標物件的,透過該方法我們可以返回目標物件本身,也可以返回一個它的代理,可以決定是否要進行攔截進而決定要返回一個什麼樣的目標物件,官方提供了示例:return Plugin。 wrap(target, this);

intercept 方法就是要進行攔截的時候要執行的方法。

自定義外掛實現示例:

官方外掛實現:

@Intercepts({@Signature(type = Executor。 class, method = “query”,

args = {MappedStatement。 class, Object。 class, RowBounds。 class, ResultHandler。 class})})

public class TestInterceptor 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);

}

}

====================================================================

十四。 RabbitMQ模組

135。RabbitMQ 的使用場景有哪些?

搶購活動,削峰填谷,防止系統崩塌。

延遲資訊處理,比如 10 分鐘之後給下單未付款的使用者傳送郵件提醒。

解耦系統,對於新增的功能可以單獨寫模組擴充套件,比如使用者確認評價之後,新增了給使用者返積分的功能,這個時候不用在業務程式碼裡新增新增積分的功能,只需要把新增積分的介面訂閱確認評價的訊息佇列即可,後面再新增任何功能只需要訂閱對應的訊息佇列即可。

136。RabbitMQ 有哪些重要的角色?

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

生產者:訊息的建立者,負責建立和推送資料到訊息伺服器;

消費者:訊息的接收方,用於處理資料和確認訊息;

代理:就是 RabbitMQ 本身,用於扮演“快遞”的角色,本身不生產訊息,只是扮演“快遞”的角色。

137。RabbitMQ 有哪些重要的元件?

ConnectionFactory(連線管理器):應用程式與Rabbit之間建立連線的管理器,程式程式碼中使用。

Channel(通道):訊息推送使用的通道。

Exchange(交換器):用於接受、分配訊息。

Queue(佇列):用於儲存生產者的訊息。

RoutingKey(路由鍵):用於把生成者的資料分配到交換器上。

BindingKey(繫結鍵):用於把交換器的訊息繫結到佇列上。

138。RabbitMQ 中 vhost 的作用是什麼?

vhost:每個 RabbitMQ 都能建立很多 vhost,我們稱之為虛擬主機,每個虛擬主機其實都是 mini 版的RabbitMQ,它擁有自己的佇列,交換器和繫結,擁有自己的許可權機制。

139。RabbitMQ 的訊息是怎麼傳送的?

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

140。RabbitMQ 怎麼保證訊息的穩定性?

提供了事務的功能。

透過將 channel 設定為 confirm(確認)模式。

141。RabbitMQ 怎麼避免訊息丟失?

把訊息持久化磁碟,保證伺服器重啟訊息不丟失。

每個叢集中至少有一個物理磁碟,保證訊息落入磁碟。

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

宣告佇列必須設定持久化 durable 設定為 true。

訊息推送投遞模式必須設定持久化,deliveryMode 設定為 2(持久)。

訊息已經到達持久化交換器。

訊息已經到達持久化佇列。

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

143。RabbitMQ 持久化有什麼缺點?

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

144。RabbitMQ 有幾種廣播型別?

direct(預設方式):最基礎最簡單的模式,傳送方把訊息傳送給訂閱方,如果有多個訂閱者,預設採取輪詢的方式進行訊息傳送。

headers:與 direct 類似,只是效能很差,此型別幾乎用不到。

fanout:分發模式,把消費分發給所有訂閱者。

topic:匹配訂閱模式,使用正則匹配到訊息佇列,能匹配到的都能接收到。

145。RabbitMQ 怎麼實現延遲訊息佇列?

延遲佇列的實現有兩種方式:

透過訊息過期後進入死信交換器,再由交換器轉發到延遲消費佇列,實現延遲功能;

使用 RabbitMQ-delayed-message-exchange 外掛實現延遲功能。

146。RabbitMQ 叢集有什麼用?

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

高可用:某個伺服器出現問題,整個 RabbitMQ 還可以繼續使用;

高容量:叢集可以承載更多的訊息量。

147。RabbitMQ 節點的型別有哪些?

磁碟節點:訊息會儲存到磁碟。

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

148。RabbitMQ 叢集搭建需要注意哪些問題?

各節點之間使用“–link”連線,此屬性不能忽略。

各節點使用的 erlang cookie 值必須相同,此值相當於“秘鑰”的功能,用於各節點的認證。

整個叢集中必須包含一個磁碟節點。

149。RabbitMQ 每個節點是其他節點的完整複製嗎?為什麼?

不是,原因有以下兩個:

儲存空間的考慮:如果每個節點都擁有所有佇列的完全複製,這樣新增節點不但沒有新增儲存空間,反而增加了更多的冗餘資料;

效能的考慮:如果每條訊息都需要完整複製到每一個叢集節點,那新增節點並沒有提升處理訊息的能力,最多是保持和單節點相同的效能甚至是更糟。

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。資料庫的三正規化是什麼?

第一正規化(1NF):強調的是列的原子性,即資料庫表的每一列都是不可分割的原子資料項。

第二正規化(2NF):要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性。(在1NF基礎上消除非主屬性對主鍵的部分函式依賴)

第三正規化(3NF):任何非主屬性不依賴於其它非主屬性。(在2NF基礎上消除傳遞依賴)

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 個是空位元組。

優點:效率高;缺點:佔用空間;適用場景:儲存密碼的 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

1

可用的配置值: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 是一個使用 C 語言開發的快取記憶體資料庫。

redis是一個key-value儲存系統。和Memcached類似,它支援儲存的value型別相對更多,包括string(字串)、list(連結串列)、set(集合)、zset(sorted set ——有序集合)和hash(雜湊型別)。這些資料型別都支援push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支援各種不同方式的排序。與memcached一樣,為了保證效率,資料都是快取在記憶體中。區別的是redis會週期性的把更新的資料寫入磁碟或者把修改操作寫入追加的記錄檔案,並且在此基礎上實現了master-slave主從同步【主從同步:資料可以從主伺服器向任意數量的從伺服器上同步】。

Redis 是一個高效能的key-value資料庫。redis的出現,很大程度補償了memcached這類key/value儲存的不足,在部 分場合可以對關係資料庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。

Redis 使用場景:

記錄帖子點贊數、點選數、評論數;

快取近期熱帖;

快取文章詳情資訊;

記錄使用者會話資訊。

180。Redis 有哪些功能?

資料快取功能

分散式鎖的功能

支援資料持久化

支援事務

支援訊息佇列

181。Redis 和 memcache 有什麼區別?

儲存方式不同:memcache 把資料全部存在記憶體之中,斷電後會掛掉,資料不能超過記憶體大小;Redis 有部份存在硬碟上,這樣能保證資料的永續性。

資料支援型別:memcache 對資料型別支援相對簡單;Redis 有複雜的資料型別。

使用底層模型不同:它們之間底層實現方式,以及與客戶端之間通訊的應用協議不一樣,Redis 自己構建了 vm 機制,因為一般的系統呼叫系統函式的話,會浪費一定的時間去移動和請求。

value 值大小不同:Redis 最大可以達到 1gb;memcache 只有 1mb。

182。Redis 為什麼是單執行緒的?

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

關於 Redis 的效能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求。而且單執行緒並不代表就慢, nginx 和 node。js 也都是高效能單執行緒的代表。

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

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

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

184。Redis 支援的資料型別有哪些?

Redis 支援的資料型別:string(字串)、list(列表)、hash(字典)、set(集合)、zset(有序集合)。

185。Redis 支援的 Java 客戶端都有哪些?

支援的 Java 客戶端有 Redisson、jedis、lettuce 等。

186。jedis 和 Redisson 有哪些區別?

jedis:提供了比較全面的 Redis 命令的支援。

Redisson:實現了分散式和可擴充套件的 Java 資料結構,與 jedis 相比 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 如何做記憶體最佳化?

儘量使用 Redis 的散列表,把相關的資訊放到散列表裡面儲存,而不是把每個欄位單獨儲存,這樣可以有效的減少記憶體使用。比如將 Web 系統的使用者物件,應該放到散列表裡面再整體儲存到 Redis,而不是把使用者的姓名、年齡、密碼、郵箱等欄位分別設定 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 主從複製的效能問題,為了主從複製的速度和連線的穩定性,主從庫最好在同一個區域網內。

···

====================================================================

2019最新整理208道JAVA面試題(附答案)續

十九。 JVM模組

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

類載入器(ClassLoader)

執行時資料區(Runtime Data Area)

執行引擎(Execution Engine)

本地庫介面(Native Interface)

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

195。說一下 JVM 執行時資料區?

不同虛擬機器的執行時資料區可能略微有所不同,但都會遵從 Java 虛擬機器規範, Java 虛擬機器規範規定的區域分為以下 5 個部分:

程式計數器(Program Counter Register):當前執行緒所執行的位元組碼的行號指示器,位元組碼解析器的工作是透過改變這個計數器的值,來選取下一條需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能,都需要依賴這個計數器來完成;

Java 虛擬機器棧(Java Virtual Machine Stacks):用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊;

本地方法棧(Native Method Stack):與虛擬機器棧的作用是一樣的,只不過虛擬機器棧是服務 Java 方法的,而本地方法棧是為虛擬機器呼叫 Native 方法服務的;

Java 堆(Java Heap):Java 虛擬機器中記憶體最大的一塊,是被所有執行緒共享的,幾乎所有的物件例項都在這裡分配記憶體;

方法區(Methed Area):用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯後的程式碼等資料。

196。說一下堆疊的區別?

功能方面:堆是用來存放物件的,棧是用來執行程式的。

共享性:堆是執行緒共享的,棧是執行緒私有的。

空間大小:堆大小遠遠大於棧。

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

佇列和棧都是被用來預儲存資料的。

佇列允許先進先出檢索元素,但也有例外的情況,Deque 介面允許從兩端檢索元素。

棧和佇列很相似,但它執行對元素進行後進先出進行檢索。

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

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

類載入器分類:

啟動類載入器(Bootstrap ClassLoader),是虛擬機器自身的一部分,用來載入Java_HOME/lib/目錄中的,或者被 -Xbootclasspath 引數所指定的路徑中並且被虛擬機器識別的類庫;

其他類載入器:

擴充套件類載入器(Extension ClassLoader):負責載入\lib\ext目錄或Java。 ext。 dirs系統變數指定的路徑中的所有類庫;

應用程式類載入器(Application ClassLoader)。負責載入使用者類路徑(classpath)上的指定類庫,我們可以直接使用這個類載入器。一般情況,如果我們沒有自定義類載入器預設就是用這個載入器。

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

199。說一下類裝載的執行過程?

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

載入:根據查詢路徑找到相應的 class 檔案然後匯入;

檢查:檢查載入的 class 檔案的正確性;

準備:給類中的靜態變數分配記憶體空間;

解析:虛擬機器將常量池中的符號引用替換成直接引用的過程。符號引用就理解為一個標示,而在直接引用直接指向記憶體中的地址;

初始化:對靜態變數和靜態程式碼塊執行初始化工作。

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

一般有兩種方法來判斷:

引用計數器:為每個物件建立一個引用計數,有物件引用時計數器 +1,引用被釋放時計數 -1,當計數器為 0 時就可以被回收。它有一個缺點不能解決迴圈引用的問題;

可達性分析:從 GC Roots 開始向下搜尋,搜尋所走過的路徑稱為引用鏈。當一個物件到 GC Roots 沒有任何引用鏈相連時,則證明此物件是可以被回收的。

201。Java 中都有哪些引用型別?

強引用:發生 gc 的時候不會被回收。

軟引用:有用但不是必須的物件,在發生記憶體溢位之前會被回收。

弱引用:有用但不是必須的物件,在下一次GC時會被回收。

虛引用(幽靈引用/幻影引用):無法透過虛引用獲得物件,用 PhantomReference 現虛引用,虛引用的用途是在 gc 時返回一個通知。

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 詳細資訊。

小編這裡還整理了更多相關的學習資料和學習影片,

私信我:學習,可免費領取。