1. 程式人生 > >【面試】PHP/JAVA等後端面試題

【面試】PHP/JAVA等後端面試題

根據自己的經驗總結了一些面試經驗,大家可以參考下,一般來說後端的東西都差不多,而語言的不同是次要的。

1. mysql儲存引擎

myisam: 不支援事務安全、不支援外來鍵、表級鎖機制、B-tree、快讀
innodb: 事務安全、有commit/rollback機制、支援外來鍵、行級鎖、也支援表級鎖、b+tree、完整事務支援;
memory: 表儲存在記憶體中,雜湊索引、適合儲存臨時資料、表級鎖機制、hash/b-tree、記憶體資料;
archive: 只支援insert/select查詢、不支援delete/update等操作;

2. 事務的ACID

原子性、一致性、獨立性、持續性;

3. MYSQL鎖機制:for update

行級鎖定:併發處理上有較大的優勢、鎖定顆粒度很小、行級鎖定也最容易發生死鎖;表級鎖定:鎖定整張表、寫操作程序會阻塞讀程序、讀會阻塞對同一表的寫程序、鎖用佇列實現;

4. MYSQL索引

索引型別:

1. b-tree索引:以innodb儲存引擎為例採用B+樹索引、葉子節點儲存指向表中記錄的地址;
(1)使用:全值匹配、匹配最左字首、匹配列字首(一例值的開頭部分)、匹配取值範圍、
2. 雜湊索引:對每行的索引列會計算一個雜湊碼值,雜湊表中存放著雜湊碼和批向行的指標;
3. 全文索引:查詢的是文字中的關鍵詞,而不是直接比較索引中的值;

索引優化:

(1)獨立的例:不要包含表示式,始終將索引列單獨放在比較符號的一側;
(2)多列索引:可以能過explain命令檢視type欄位來優化自己建的索引;type:從最好到最差的連線型別為const、eq_reg、ref、range、indexhe和ALL
(3)選擇合適的索引順序:
(a)根據索引的選擇性高的放在前面會好些;

5. mysql主從複製原理

Master 與 Slave 之間的實現整個複製過程主要由三個執行緒來完成,其中兩個執行緒(SQL 執行緒和 I/O 執行緒)在 Slave 端,另外一個執行緒(I/O 執行緒)在 Master 端。
要實現 MySQL 的 Replication ,首先必須開啟 Master 端的 Binary Log,因為整個複製過程實際上就是 Slave 從 Master 端獲取該日誌然後再在自己身上完全順序的執行日誌中所記錄的各種操作。
主在執行sql之後,記錄二進位制log檔案(bin-log)。 從連線主,並從主獲取binlog,存於本地relay-log,並從上次記住的位置起執行sql,一旦遇到錯誤則停止同步。 

6. mysql中varchar與char: 

char:是固定長的;
varchar:長度是可變的;
varchar(20),指的是20字元,無論存放的是數字、字母還是UTF8漢字(每個漢字3位元組),都可以存放20個,最大大小是65532位元組 ;
區別:
char是一種固定長度的型別,varchar則是一種可變長度的型別,它們的區別是:
char(M)型別的資料列裡,每個值都佔用M個位元組,如果某個長度小於M,MySQL就會在它的右邊用空格字元補足.(在檢索操作中那些填補出來的空格字元將被去掉)在varchar(M)型別的資料列裡,每個值只佔用剛好夠用的位元組再加上一個用來記錄其長度的位元組(即總長度為L+1位元組);

7. innodb的事務與日誌的實現方式

在Innodb儲存引擎中,事務日誌是通過redo和innodb的儲存引擎日誌緩衝(Innodb log buffer)來實現的,當開始一個事務的時候,會記錄該事務的lsn(log sequence number)號;當事務執行時,會往InnoDB儲存引擎的日誌的日誌快取裡面插入事務日誌;當事務提交時,必須將儲存引擎的日誌緩衝寫入磁碟(通過innodb_flush_log_at_trx_commit來控制),也就是寫資料前,需要先寫日誌。這種方式稱為“預寫日誌方式”,innodb通過此方式來保證事務的完整性。也就意味著磁碟上儲存的資料頁和記憶體緩衝池上面的頁是不同步的,是先寫入redo log,然後寫入data file,因此是一種非同步的方式。

8. sql優化

(1)explain出來的各種item的意義: 優化索引
(2)profile的意義以及使用場景:優化SQL查詢,可以看到每條SQL的執行時間等;
(3)explain中的索引問題。

9.JAVA垃圾回收機制

(1)引用計數法

其原理是:給物件新增一個引用計數器,每當有其他地方引用它時,計數器就增1;當失去一個引用時,計數器值減1;計數器為0時則說明這個物件可以被回收;

(2)標記-清除演算法

標記-清除演算法將垃圾回收分為兩個階段:標記階段和清除階段。標記階段:首先通過根節點,標記所有從根節點開始的可達物件,未被標記的物件就是未被引用的垃圾物件;清除階段:清除所有未被標記的物件。
這個思想的意思是:在程式的起點開始就是一個根節點,隨著程式的執行就會引用不同的節點,被引用的做標記,未被引用的做清除標記,做清除標記的作為垃圾回收。
缺點:會產生空間碎片。

(3)複製演算法

這是一種高效的回收演算法,其核心思想是:
將原有的記憶體空間分為兩塊,每次只使用其中一塊,在垃圾回收時,將正在使用的記憶體中存活的物件複製到未使用的記憶體塊中,
之後,清除正在使用的記憶體塊的所有物件,然後再交換兩個記憶體的角色,這樣就完成了垃圾回收。
缺點:是當記憶體中大部分都是存活物件,那麼這種演算法都是在做無用功。

(4)標記-壓縮演算法

這是一種老年代的回收演算法,在標記-清除演算法做了改進,
也是從根節點開始,對所有物件做一次標記,對標記清除的物件不是簡單的清除,
而是先把存活物件壓縮到記憶體的一端,確定好邊界之後,再把所有的標記清除的物件全部刪除,
這樣就避免了碎片的產生,同時又不需要頻繁交換空間。

(5)增量演算法

在大部分垃圾回收過程中,一旦開始回收,應用程式所有執行緒都處在掛起狀態,時間很長的情況下,會影響使用者體驗以及效能穩定。
增量的演算法就是:如果一次性將所有垃圾進行處理,需要造成系統長時間的停頓,那麼可以讓垃圾回收執行緒與程式執行緒交替進行,
每次只回收一片區域,接著再切換到程式程序,
缺點:執行緒之間的不停切換會影響整體成本的升高。

(6)分代

分代的基本思想就是:
它將記憶體區間根據物件的特點分為幾塊,根據每塊記憶體區間的特點,使用不同的演算法,從而提高垃圾回收效率。
一般記憶體區域分為老生代和新生代,新建的物件建在新生代,常用的物件建在老生代,新生代用複製演算法,老生代用標記-壓縮演算法。
這樣兩邊的效率最高,這是目前最常用的垃圾回收演算法。

10. 分表策略

(1)預先估計某個大表的資料量,按實際情況將其均分為固定數量表;

根據分表演算法,將資料平均分散到不同的資料表中,常見處理方式有對自增id取模、對某個欄位進行hash。比如某系統使用者預計支援1億使用者數,分100個表儲存使用者資料,按照自增id的最後2位來分表,對100取模,那麼使用者資料表就是user_01~user_99。

(2)按時間拆分

對於那種根據時間增長較快的資料可以按時間拆分,根據業務實際情況按天、按月、按年等進行拆分。比如進銷存資料,我們可以按月分表,形如jxc_data_201201、jxc_data_201202

(3)按每個表固定記錄行數拆分

一般根據自增長ID拆表,每張表儲存指定數量的資料。一張表的資料行數到了指定數量,就自動儲存到新的表裡。

(4)將很久之前的資料遷移到一張歷史表

比如日誌記錄,一般只會查詢3個月之內的日誌,對於超過三個月的日誌記錄我們可以遷移到到遷移到另一張表中,比如log_history

10. java設計模式

單例模式:
	public class Single {
			//用volatile修飾的變數,執行緒在每次使用變數的時候,都會讀取變數修改後的最的值
			private volatile static Single uiqueInstance;
			private Single(){}
			public static Single getInstance(){
				if(uiqueInstance == null){
					//synchronized後面括號裡是類,此時,執行緒獲得的是類鎖
					synchronized(Single.class){
						if(uiqueInstance == null){					
							String s="single pattern";
							System.out.println(s);
							uiqueInstance = new Single();
						}
					}
				}
				return uiqueInstance;				
			}
			public static void main(String[] args) {
				// TODO Auto-generated method stub
				Single.getInstance();		
			}
		}

11. http協議的請求方式有哪些?

(1)表單提交資料組伺服器的過程

form提交的第一步是建立資料集,並根據 ENCTYPE 指定的型別值對資料集進行編碼;預設地,表單資料會編碼為 "application/x-www-form-urlencoded";
application/x-www-form-urlencoded對form資料集的編碼規則:(1)如果是字母或數字,則直接使用其ascii碼的十六進位制。(2)對於非字母也非數字的字元,則不僅使用其ascii碼的十六進位制,還要在前面加上“%”。比如“\”,它的ascii碼是92,92的十六進位制是5c,所以“\”的urlencoded編碼就是%5c;

(2)get和post的主要區別

get: form中的資料集(如input框的value)將被編碼到URL中,作為URL的一部分,在位址列上可以看到;請求任意次都返回同樣的結果)時使用GET;get傳送的資料量較小,不能大於2KB;post: form中的資料集則被編碼到http協議的header中,構造成訊息傳送;當請求會改變伺服器資料或狀態時使用POST;post傳送的資料量較大,一般被預設為不受限制;

12. SQL注入過程及防止

(1)判斷Web環境是否可以SQL注入,只有對資料庫進行動態查詢的業務才可能存在SQL注入;
(2)尋找SQL注入點,通過輸入一些特殊語句,可以根據瀏覽器返回資訊,判斷資料庫型別,從而構建資料庫查詢語句找到注入點;
(3)猜解使用者名稱和密碼。資料庫中存放的表名、欄位名都是有規律可言的。通過構建特殊資料庫語句在資料庫中依次查詢表名、欄位名、使用者名稱和密碼的長度,以及內容。
這個猜測過程可以通過網上大量注入工具快速實現,並藉助破解網站輕易破譯使用者密碼;
(4)尋找WEB管理後臺入口。通常WEB後臺管理的介面不面向普通使用者;
(5)入侵和破壞;
(6)防止:轉義或過濾一些特殊字元,如%等。引數較驗等。

13. Redis與Memcached的區別

Redis:

(1)Redis不僅僅支援簡單的k/v型別的資料,同時還提供list,set,hash等資料結構的儲存;
(2)Redis支援資料的備份,即master-slave模式的資料備份;

主從同步過程:

(a) slave伺服器主動連線到Master伺服器。
(b) slave伺服器傳送SYCN命令到Master伺服器請求同步。
(c) master伺服器備份資料庫到rdb檔案。
(d) master伺服器把rdb檔案傳輸給slave伺服器。
(e) slave伺服器清空資料庫,把rdb檔案資料匯入資料庫中。
(f) mastere伺服器把使用者所有更改資料的操作,通過命令的形式轉發給所有slave伺服器,slave伺服器只需執行master伺服器傳送過來的命令就可以達到同步的效果。
(3)Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用;
記憶體快照:是將記憶體中的資料以快照的方式寫入二進位制檔案中,預設檔名為:dump.rdb;記憶體快照每次都把記憶體資料完整地寫入硬碟,而不是 只寫入增量資料,如數量大時,寫入操作頻繁會嚴重影響效能的。設定配置項來控制寫入的間隔時間。
日誌追加:把增加、修改資料的命令通過write函式追加到檔案尾部(預設是appendonly.aof)。Redis重啟時讀取appendonly.aof檔案中的所有命令並且執行,從而把資料寫入記憶體中。
(4) redis記憶體淘汰演算法:
LRU:從資料庫中刪除一個最近最少訪問的key;
隨機淘汰演算法:從資料庫中隨機刪除一個key;
TTL淘汰演算法:從資料庫中刪除一個最快期的key;

Memcached:

(1)只有LRU記憶體淘汰演算法;
(2)只支援簡單的key/value,不支付複雜的資料結構型別;
(3)採用多執行緒模型:主執行緒接收客戶端連線,工作執行緒處理客戶端連線的請求。
(a) 主執行緒監聽客戶端的連線,有客戶端連線到memcached時,呼叫accept函式來接收到來的連線,把連線push到工作執行緒佇列中,並向工作執行緒傳送一個訊號,通知工作執行緒有新的連線要處理;
(b) 工作執行緒收到主執行緒訊號後,列會把佇列上的客戶端連線註冊到libevent進行偵聽,libevent會偵聽客戶端連線的讀寫事件,並呼叫相關的回撥函式進行處理。

14. http協議header裡有哪些資訊,瀏覽器快取控制的幾個方法?

請求header中的常見欄位:
Accept: 告訴伺服器能夠傳送哪些媒體查詢,如text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8;
Accept-Encoding: 告訴伺服器能傳送哪些編碼方式,gzip,deflate,sdch;
Accept-Language: 告訴伺服器能傳送哪些語言,zh-CN,zh;q=0.8,en;q=0.6;
Cache-Control: 快取欄位,如果指定了max-age值,那麼在此值內的時間裡就不會重新訪問伺服器,max-age=0,no-cache,則每次都重複訪問;
Expires它表示快取的存在時間,告訴客戶端瀏覽器在這個時間之前不對伺服器傳送請求,而直接使用瀏覽器的快取。 
1. public 指示響應資料可以被任何客戶端快取 
2. private 指示響應資料可以被非共享快取所快取。這表明響應的資料可以被髮送請求的瀏覽器快取,而不能被中介所快取 
3. no-cache 指示響應資料不能被任何接受響應的客戶端所快取 
4. no-store 指示所傳送的響應資料除了不能被快取,也不能存入磁碟。一般用於敏感資料,以免資料被複制。 
5. must-revalidate 指示所有的快取都必須重新驗證,在這個過程中,瀏覽器會發送一個If-Modified-Since頭。
  如果伺服器程式驗證得出當前的響應資料為最新的數 據,那麼伺服器應當返回一個304 Not Modified響應給客戶端,否則響應資料將再次被髮送到客戶端。 
6. proxy-revalidate 與must-revalidate相似,不同的是用來指示共享快取。 
7. max-age 資料經過max-age設定的秒數後就會失效,相當於HTTP/1.0中的Expires頭。如果在一次響應中同時設定了max-age和 Expires,那麼max-age將具有較高的優先順序。 
8. s-maxage 與max-age相似,不同的是用來指示共享快取。 
Connection: 連線型別,keep-alive:長連線,closed:不用長連結;
Cookie:安全首部,由客戶端傳送,包含在HTTP請求的頭部中;
Host: 主機,tuan.baidu.com;
Referer: 告訴伺服器我是從哪個頁面連結過來的,http://tuan.baidu.com/
User-Agent: 瀏覽器及作業系統的資訊,Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
響應header中的常見欄位:
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/html
Date:Fri, 21 Mar 2014 10:50:46 GMT
Server:Apache
Set-Cookie:由伺服器傳送,它包含在響應請求的頭部中。它用於在客戶端建立一個Cookie,tn=baidutuan_tg; path=/
Content-Length:首部告訴瀏覽器報文中實體主體的大小,Content-Length就是壓縮後的大小,HTTP協議中使用Content-Length這個頭來告知資料的長度。
然後,在資料下行的過程中,Content-Length的方式要預先在伺服器中快取所有資料,然後所有資料再一股腦兒地發給客戶端。
果要一邊產生資料,一邊發給客戶端,WEB 伺服器就需要使用"Transfer-Encoding: chunked"這樣的方式來代替Content-Length。
Vary: Vary中有User-Agent,那麼即使相同的請求,如果使用者使用IE打開了一個頁面,再用Firefox開啟這個頁面的時候,代理/客戶端會認為這是不同的頁面
 如果Vary中沒有User-Agent,那麼代理/客戶端快取會認為是相同的頁面,直接給使用者返回快取的內容,而不會再去web伺服器請求相應的頁面Accept-Encoding;

15. 如何實現一個執行緒?

(1)需要從Java.lang.Thread類派生一個新的執行緒類,過載它的run()方法;
利用擴充套件Thread類建立的多個執行緒,雖然執行的是相同的程式碼,但彼此相互獨立,且各自擁有自己的資源,互不干擾;
(2)實現Runnalbe介面,過載Runnalbe介面中的run()方法。別適合多個具有相同程式碼的執行緒去處理同一資源的情況;

16. 記憶體溢位

記憶體溢位是指應用系統中存在無法回收的記憶體或使用的記憶體過多,最終使得程式執行要用到的記憶體大於虛擬機器能提供的最大記憶體;
原因:
(1)記憶體中載入的資料量過於龐大,如一次從資料庫取出過多資料,如與資料庫鎖表有關;
(2)程式碼中存在死迴圈或迴圈產生過多重複的物件實體;
(3)啟動引數記憶體值設定的過小;
解決:
(1)就是修改JVM啟動引數,直接增加記憶體;
(2)檢查錯誤日誌;
(3)使用記憶體檢視工具動態檢視記憶體使用情況;

17. Heap memory和Stack memory的區別

(1)Heap Memory是堆記憶體,Stack Memory是棧記憶體;
(2)Stack memory記憶體空間由作業系統自動分配和釋放,Heap Memory記憶體空間手動申請和釋放的,Heap Memory記憶體常用new關鍵字來分配;
(3)Stack Memory記憶體空間有限,Heap Memor的空間是很大的自由區幾乎沒有空間限制;
(4)堆記憶體由Java 虛擬機器的自動垃圾回收器來管理,棧記憶體是當超過變數的作用域後,Java 會自動釋放掉為該變數分配的記憶體空間,該記憶體空間可以立即被另作它用。

18. 非遞迴後續遍歷二叉樹

// 後序遍歷虛擬碼:非遞迴版本,用棧實現
		void PostOrder(TNode* root)
		{
			Stack S;
			if( root != NULL )
			{
				S.push(root);
			}
			while ( !S.empty() )
			{
				TNode* node = S.pop(); 
				if ( node->bPushed )
				{   // 如果標識位為true,則表示其左右子樹都已經入棧,那麼現在就需要訪問該節點了
					Visit(node);        
				}
				else
				{   // 左右子樹尚未入棧,則依次將 右節點,左節點,根節點 入棧
					if ( node->right != NULL )
					{
						node->right->bPushed = false; // 左右子樹均設定為false
						S.push(node->right);
					}
					if ( node->left != NULL )
					{
						node->left->bPushed = false;
						S.push(node->left);
					}
					node->bPushed = true;            // 根節點標誌位為true
					S.push(node);
				}
			}
		}

19. Throwable、Error、Exception以及RuntimeException的區別

(1)Throwable類是 Java 語言中所有錯誤或異常的超類。它的兩個子類是Error和Exception;
(2)Error是Throwable 的子類,用於指示合理的應用程式不應該試圖捕獲的嚴重問題。大多數這樣的錯誤都是異常條件;
(3)Exception類及其子類是 Throwable 的一種形式,它指出了合理的應用程式想要捕獲的條件;
(4)RuntimeException是那些可能在 Java 虛擬機器正常執行期間丟擲的異常的超類。
可能在執行方法期間丟擲但未被捕獲的RuntimeException 的任何子類都無需在 throws 子句中進行宣告。它是Exception的子類;

(資料會持續更新。。。。)