1. 程式人生 > >資料庫面試必備

資料庫面試必備

正規化

     正規化是“符合某一種級別的關係模式的集合,表示一個關係內部各屬性之間的聯絡的合理化程度”。 符合高一級正規化的設計,必定符合低一級正規化,例如符合2NF的關係模式,必定符合1NF。

1NF符合1NF關係中的每個屬性(資料庫中的每一列)都不可再分。對應我們設計就是不能出現重複的列。這個是關係資料庫的基礎沒有人會犯這個錯誤(資料庫也不讓)。

2NF在1NF的基礎之上,消除了非主屬性對於碼的部分函式依賴。第二正規化需要確保資料庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。

      第二正規化的意義:是為了消除冗餘資訊,若存在部分函式依賴,那麼該屬性是沒必要存在這張表的,確定了被依賴的那個屬性,就確定了該屬性,沒必要反覆存在這張表中,新建一張表來存具有依賴關係的這兩個屬性就好了。

    傳遞函式依賴:假如在『Y 不包含於 X,且 X 不函式依賴於 Y』這個前提下,Z 函式依賴於 Y,且 Y 函式依賴於 X ,那麼我們就稱 Z 傳遞函式依賴於 X ,記作 X T→ Z 。

     候選碼/:設 K 為某表中的一個屬性或屬性組,若除 K 之外的所有屬性都完全函式依賴於 K,那麼我們稱 K 為候選碼,簡稱為碼。在實際中我們通常可以理解為:假如當 K 確定的情況下,該表除 K 之外的所有屬性的值也就隨之確定,那麼 K 就是碼。包含在任何一個碼中的屬性成為主屬性。主屬性,候選碼,都是唯一的意思(也就是資料庫中的主鍵)。

3NF在2NF的基礎之上,消除了非主屬性對於碼的傳遞函式依賴

。任意兩個表,不能出現重複的非主鍵欄位 。

    第三正規化的意義:符合3NF要求的資料庫設計,基本上解決了資料冗餘過大,插入異常,修改異常,刪除異常的問題。根據實體完整性的要求,主屬性不能為空。

BCNF:在 3NF 的基礎上,消除主屬性對於碼的部分與傳遞函式依賴,即為了應對存在多個碼時,主屬性之間的冗餘問題。

總結:

1NF: 欄位是最小的的單元不可再分 ;

2NF:滿足1NF,表中的欄位必須完全依賴於全部主鍵而非部分主鍵 (一般我們都會做到) ;

3NF:滿足2NF,非主鍵外的所有欄位必須互不依賴;

BCNF:滿足3NF,消除表中的多值依賴 。

    越高等級的正規化所產生的表越多,而在應用程式使用的過程中越多的表Join和查詢造成的效能損耗的問題,甚至很多情況下為了兼顧效能和開發我們甚至要做一下反正規化的操作,所以一般認為超過第三正規化都是多餘的,所以再實際工作中不能太過教條!!!

資料庫事務和隔離級別

資料庫事務

     簡單的說就是把對資料庫的一系列操作放到一個可控制的過程中,進行可量化的控制。事務有4個必須的屬性原則ACID:

     ▲原子性(Atomicity):必須保證在一個事務中的操作要麼全部執行,要麼全部不執行。

     ▲一致性(Consistency):事務操作在完成時必須使資料庫保持一致的狀態,內部資料結構必須是完整的。比如一個例子 A和B都有50塊錢,他們兩個無論怎麼進行相互轉賬,A+B始終是100。

     ▲隔離性(Isolation):簡單的來說就是各個事務之間的影響程度。

     ▲永續性(Durability):不管資料庫是否發生問題,事務在完成之後資料應該永遠的儲存在資料庫中。

事務之間是會相互影響的,這時候需要有一個規則來約束事務操作,於是有了事務隔離。

事務隔離級別(4種),由低到高依次為:

    ■Read uncommitted(讀未提交) :避免了更新丟失,卻可能出現髒讀。也就是說事務B讀取到了事務A未提交的資料 。

     A進行了一條資料操作,但是沒有提交事務,這時如果B進行這條資料查詢,是可以查到A的資料操作的,但是這時候A還沒有提交事務,如果A不提交或者進行了事務回滾,那麼B查詢到的資料就是髒資料。

    ■Read committed(讀提交):避免了髒讀,但是可能出現不可重複讀。事務A事先讀取了資料,事務B緊接著更新了資料,並提交了事務,而事務A再次讀取該資料時,資料已經發生了變化。 

      A正在進行資料操作,還沒有提交事務,B這個時候也去查詢了A操作的這個資料,並且修改了,馬上提交了事務,這時候A再去提交事務的時候會發現資料不對了,因為A手上的資料是B沒修改之前的,現在去提交時,資料庫的資料已經變成B更改之後的了,這種場景發生在金錢上會有很大問題,明明卡上有錢的A去消費,結果B搶在A前面消費完了,這時候A就是沒法付賬了。這就是不可重複讀。

    ■Repeatable read(重複讀):避免了不可重複讀和髒讀,但是有時可能出現幻讀。可以通過“共享讀鎖”和“排他寫鎖”實現。 

     這種情況只會發生在有一個事務在新增操作,比如A在查自己的銀行卡現在是100塊錢,A表示看花了,想再查一次,這時候有個人在給他轉賬,然後A第二次查詢,查出了1000塊了,又不敢相信自己是不是看花了。這就是幻讀。

    ■Serializable(序列化,也叫序列化):事務只能一個接著一個地執行,但不能併發執行。 可以解決幻讀問題 。

     Serializable是最高的事務隔離級別,同時代價也花費最高,效能很低,一般很少使用,在該級別下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻像讀。

    對於大多數應用程式,可以優先考慮把資料庫的隔離級別設定為read committed。可以避免髒讀,而且有較好的併發效能。儘管可能導致不可重複讀、幻讀和第二類丟失更新這些併發問題。可以由應用程式採用悲觀鎖或樂觀鎖來控制。MySQL預設的隔離級別就是repeatable read。 

為什麼要鎖、鎖定分類、鎖粒度

對於鎖和鎖粒度可以看下面的比喻:

    為什麼要加鎖?加鎖是為了防止不同的執行緒訪問同一共享資源造成混亂。打個比方:人是不同的執行緒,衛生間是共享資源。你在上洗手間的時候肯定要把門鎖上吧,這就是加鎖,只要你在裡面,這個衛生間就被鎖了,只有你出來之後別人才能用。想象一下如果衛生間的門沒有鎖會是什麼樣?     什麼是加鎖粒度呢?所謂加鎖粒度就是你要鎖住的範圍是多大。比如你在家上衛生間,你只要鎖住衛生間就可以了吧,不需要將整個家都鎖起來不讓家人進門吧,衛生間就是你的加鎖粒度。     怎樣才算合理的加鎖粒度呢?其實衛生間並不只是用來上廁所的,還可以洗澡,洗手。這裡就涉及到優化加鎖粒度的問題。 你在衛生間裡洗澡,其實別人也可以同時去裡面洗手,只要做到隔離起來就可以,如果馬桶,浴缸,洗漱臺都是隔開相對獨立的,實際上衛生間可以同時給三個人使用,當然三個人做的事兒不能一樣。這樣就細化了加鎖粒度,你在洗澡的時候只要關上浴室的門,別人還是可以進去洗手的。如果當初設計衛生間的時候沒有將不同的功能區域劃分隔離開,就不能實現衛生間資源的最大化使用。這就是設計架構的重要性。

為什麼加鎖

     如何保證資料併發訪問的一致性、有效性是所在有資料庫必須解決的一個問題,鎖衝突也是影響資料庫併發訪問效能的一個重要因素,鎖對資料庫而言顯得尤其重要,也更加複雜。防止更新丟失,並不能單靠資料庫事務控制器來解決,需要應用程式對要更新的資料加必要的鎖來解決。

鎖定機制分類:

    鎖定機制就是資料庫為了保證資料的一致性而使各種共享資源在被併發訪問,訪問變得有序所設計的一種規則。MySQL資料庫由於其自身架構的特點,存在多種資料儲存引擎,每種儲存引擎所針對的應用場景特點都不太一樣,為了滿足各自特定應用場景的需求,每種儲存引擎的鎖定機制都是為各自所面對的特定場景而優化設計,所以各儲存引擎的鎖定機制也有較大區別。

按封鎖型別分類(資料物件可以是表可以是記錄)

    1)排他鎖(又稱寫鎖,X鎖)

      會阻塞其他事務讀和寫。若事務T對資料物件A加上X鎖,則只允許T讀取和修改A,其他任何事務都不能再對加任何型別的鎖,知道T釋放A上的鎖。這就保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。

    2)共享鎖(又稱讀取,S鎖)

      會阻塞其他事務修改表資料。若事務T對資料物件A加上S鎖,則其他事務只能再對A加S鎖,而不能X鎖,直到T釋放A上的鎖。這就保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

X鎖和S鎖都是載入某一個數據物件上的。也就是資料的粒度。

按封鎖的資料粒度分類如下:

    1)行級鎖定(row-level)開銷大加鎖慢會出現死鎖鎖定粒度最小發生鎖衝突的概率最低,併發度也最高

行級鎖定最大的特點就是鎖定物件的顆粒度很小,也是目前各大資料庫管理軟體所實現的鎖定顆粒度最小的。由於鎖定顆粒度很小,所以發生鎖定資源爭用的概率也最小,能夠給予應用程式儘可能大的併發處理能力而提高一些需要高併發應用系統的整體效能。

缺陷由於鎖定資源的顆粒度很小,所以每次獲取鎖和釋放鎖需要做的事情也更多,帶來的消耗自然也就更大了。此外,行級鎖定也最容易發生死鎖。

    2)表級鎖定(table-level)開銷小,加鎖快;不會出現死鎖鎖定粒度大發生鎖衝突的概率最高併發度最低

和行級鎖定相反,表級別的鎖定是MySQL各儲存引擎中最大顆粒度的鎖定機制。該鎖定機制最大的特點是實現邏輯非常簡單,帶來的系統負面影響最小。所以獲取鎖和釋放鎖的速度很快。由於表級鎖一次會將整個表鎖定,所以可以很好的避免困擾我們的死鎖問題。

缺陷:鎖定顆粒度大所帶來最大的負面影響就是出現鎖定資源爭用的概率也會最高,致使併發度大打折扣。

     3)頁級鎖定(page-level)MySQL特有開銷和加鎖時間界於表鎖和行鎖之間會出現死鎖鎖定粒度界於表鎖和行鎖之間,併發度一般

頁級鎖定是MySQL中比較獨特的一種鎖定級別,在其他資料庫管理軟體中也並不是太常見。頁級鎖定的特點是鎖定顆粒度介於行級鎖定與表級鎖之間,所以獲取鎖定所需要的資源開銷,以及所能提供的併發處理能力也同樣是介於上面二者之間。

      缺陷:頁級鎖定和行級鎖定一樣,會發生死鎖。

    對於不可重複讀,只需採取行級鎖防止該記錄資料被更改或刪除,然而對於幻讀必須加表級鎖,防止在這個表中新增一條資料。

樂觀鎖、悲觀鎖的概念和實現方式

常見的四種鎖:

    1、樂觀鎖:每次去找資料庫拿資料都認為別人不會對資料做什麼更改,所以不會上鎖。但是在找資料庫要資料的時候會帶一個數據版本過來,做更新的時候會去把拿到的這個版本與資料庫現在的要修改的資料版本做對比 只有大於或者等於資料庫中的資料版本,那麼它就認為這次操作是對的,可以執行。否則就不執行。

    2、悲觀鎖(for update):每次去找資料庫拿資料都認為別人會改,所以它在查詢的時候就給資料加鎖,其他人只能查詢資料不能對資料做修改,只能等加鎖的人操作完成之後才會釋放鎖。 樂觀鎖適用於寫比較少的情況下,即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生衝突,上層應用會不斷的進行retry,這樣反倒是降低了效能,所以這種情況下用悲觀鎖就比較合適。

    3、共享鎖:又稱讀鎖,若事務T對資料物件A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改 。

    4、排它鎖:又稱寫鎖。若事務T對資料物件A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。這保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。

    悲觀鎖,它是一種保守型鎖,當一個事務獲取到了一個數據的悲觀鎖之後,其他的事務就再也無法對該資料進行操作。也就是傳統意義上的鎖。 樂觀鎖不同於悲觀鎖,它的主要特點在於它更加寬鬆,它維持了一個version欄位,如果一個事務獲取到了樂觀鎖,那麼在讀取資料時,會連帶著將這個version欄位一起讀出來。如果要對這個資料進行update操作,那麼就會對記憶體中的version+1,再丟回資料庫去進行比對,如果記憶體中的verison比資料庫中的version欄位大,那麼就准許更新,否則就拒絕該更新操作。

MySQL、Oracle如何實現分頁

     mysql實現分頁的方式: limit start(即起始行),count(即每一頁的最大記錄數)。引數值不能在語句當中寫計算表示式,寫到語句之前必須計算好值。 如果資料量比較小,10w以下,直接簡單的使用這種方式就行了。

   如果資料量比較大,特別是100w以上的資料量,用上面那種方式在最後的一些分頁獲取時特別慢,eg:limit 1200000,1000; LIMIT語句的偏移量就會越大,速度也會明顯變慢。

改進方式:

每次獲取主鍵id,並對結果集做一個id排序,where條件里加上id>上一次的最大id,limit可以寫成固定的limit 0,2000

這樣做的好處就是每次都會用到primary key,並且過濾掉之前已獲取的資料,每次只需要獲取最前面的2000條資料即可,效率大大提升,每次分頁的耗時基本都是一樣的。

SELECT id,product_id,merchant_id,chinese_name,english_name,

subtitle,is_deleted,is_available,create_time,CODE,

company_id,merchant_series_id,tax_no,TYPE,sale_type,

     IF (datediff(NOW(), create_time) > 14,0,1) AS isNew

FROM merchant_product

WHERE is_deleted = 0  AND is_available = 1  AND is_vendible = 1  AND STATUS = 4  AND id > #maxId# order by id

LIMIT 0,2000;

如果後面要join其他表b的話,可以where a_id<=maxId and a_id>=minId

條件加上,然後b表的a_id欄位有索引的話,查詢速度就很快了。

Oracle:

select * from (
  select rownum rn,a.* from table_name a where rownum <= x  //結束行,x = startPage*pageSize
)  where rn >= y; //起始行,y = (startPage-1)*pageSize+1

注:(1)>= y,<= x表示從第y行(起始行)~x行(結束行) 。

       (2)rownum只能比較小於,不能比較大於,因為rownum是先查詢後排序的,例如你的條件為rownum>1,當查詢到第一條資料,rownum為1,則不符合條件。第2、3...類似,一直不符合條件,所以一直沒有返回結果。所以查詢的時候需要設定別名,然後查詢完成之後再通過呼叫別名進行大於的判斷。  

用一張大表讀取資料,如何解決效能問題

1.百萬資料下查詢方面

先來看下MySQL中兩種查詢引擎查詢速度:

    InnoDB 中不儲存表的具體行數,即執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行。MyISAM只要簡單的讀出儲存好的行數即可。注意的是,當count(*)語句包含 where條件時,兩種表的操作有些不同,InnoDB型別的表用count(*)或者count(主鍵),加上where col 條件。其中col列是表的主鍵之外的其他具有唯一約束索引的列,這樣查詢時速度會很快,也就是可以避免全表掃描。

總結:mysql 在300萬條資料(myisam引擎)情況下使用 count(*) 進行資料總數查詢包含條件(正確設定索引)執行時間正常。對於經常進行讀取的資料,建議使用myIsam引擎。

2.百萬資料下分頁問題

在開發過程中我們經常會使用分頁,核心技術是使用limit進行資料的讀取,在使用limit進行分頁的測試過程中,得到以下資料:

select * from news order by id desc limit 0,10
耗時0.003秒
select * from news order by id desc limit 10000,10
耗時0.058秒
select * from news order by id desc limit 100000,10 
耗時0.575秒
select * from news order by id desc limit 1000000,10
耗時7.28秒

mysql在資料量大的情況下分頁起點越大查詢速度越慢,100萬條起的查詢速度已經需要7秒鐘。這是一個我們無法接受的數值!

改進方案1

select * from news 
where id >  (select id from news order by id desc  limit 1000000, 1)
order by id desc 
limit 0,10

    查詢時間 0.365秒,提升效率是非常明顯的!原理是什麼呢?我們使用條件對id進行了篩選,在子查詢 (select id from news order by id desc limit 1000000, 1) 中我們只查詢了id這一個欄位比起select * 或 select 多個欄位節省了大量的查詢開銷!:

改進方案2(適合id連續的系統,速度極快;不適合帶有條件的、id不連續的查詢。):

select * from news 
where id  between 1000000 and 1000010 
order by id desc

3.百萬資料下,MySQL條件查詢、分頁查詢的注意事項。

select id from news 
where cate = 1
order by id desc 
limit 500000 ,10 

     查詢時間 20 秒,好恐怖的速度!利用上面分頁查詢優化方式1進行優化:

select * from news
where cate = 1 and id > (select id from news where cate = 1 order by id desc limit 500000,1 ) 
order by id desc 
limit 0,10 

     查詢時間 15 秒,優化效果不明顯,條件帶來的影響還是很大!在這樣的情況下無論我們怎麼去優化sql語句就無法解決執行效率問題。那麼換個思路:建立一個索引表,只記錄文章的id、分類資訊,我們將文章內容這個大欄位分割出去。

    新建表 news2 [ 文章表 引擎 myisam 字符集 utf-8 ]  ,兩個欄位:id int 11 主鍵 自動增加、cate int 11 索引。在寫入資料時將2張表同步,查詢是則可以使用news2 來進行條件查詢:

select * from news
where cate = 1 and id > (select id from news2 where cate = 1 order by id desc limit 500000,1 ) 
order by id desc 
limit 0,10

    注意條件 id > 後面使用了news2 這張表!  執行時間 1.23秒,我們可以看到執行時間縮減了近20倍!!資料在10萬左右是查詢時間可以保持在0.5秒左右,是一個逐步接近我們能夠容忍的值!

    但是1秒對於伺服器來說依然是一個不能接受的值!!還有什麼可以優化的辦法嗎??我們嘗試了一個偉大的變化:將 news2 的儲存引擎改變為innodb,執行結果是驚人的!只需要 0.2秒,非常棒的速度。

內連線、左連線、右連線的作用及區別

  1. 左連線:左邊有的,右邊沒有的為null,A LEFT JOIN B,連線查詢的資料,在A中必須有,在B中可以有可以沒有。
  2. 右連線:左邊沒有的,右邊有的為null。與左連線相反。
  3. 內連線:顯示左邊右邊共有的,即A INNER JOIN B ,在A中也有,在B中也有的資料才能查詢出來。

補充:還有一中叫自連線,自連線(self join)可能看起來有點晦澀難懂,但是實際上換個角度你就會豁然開朗,你可以把它這個過程想象成兩張一樣的表進行左連線或右連線,這樣就會簡單多了,其中一張表通過設別名的方式成為了虛表,但是共享原標中的資訊。應用場景是這樣的,就是表的一個欄位和另一個欄位是相同性質的東西,譬如員工與上司,他們本質也都是員工,在員工表中,員工的直接上司編號會以另一個欄位的形式出現,但是他的上司的編號也是會出現在員工編號這個欄位裡。那麼在這種情況下,假如需要去查詢某一位員工的上司的資訊,在已知該員工編號的條件下,可以根據他的編號去獲得上司的編號,進而通過上司的編號去獲得上司的資訊。

    上面的表名為Employee,那麼我要查詢李四的上司的資訊,對應的sql語句應該是這樣的:

     select *from  Employee e1 left join Employee e2 on e1.empLeaderId=e2.empId where e1.empId=2;

Statement和PreparedStatement之間的區別

兩者關係: PreparedStatement介面繼承自Statement介面,以下是兩者區別:

PreparedStatement提高了程式碼的可讀性和可維護性

   PreparedStatement使用佔位符,容易理解,可讀性強,而使用Statement使用的字串拼接,麻煩而且過長時可讀性差。

● PreparedStatement效能更高

     建立PreparedStatement物件時使用SQL語句做引數,會解析並編譯SQL語句,也可以使用佔位符“?”的SQL語句做引數,在通過setXxx()方法給佔位符賦值後執行SQL語句時無須再解析和編譯SQL語句,是直接執行的。當進行批處理(多次執行相同操作)時,效率高。而建立Statement物件不使用SQL引數,不會解析並編譯SQL語句,每次呼叫執行SQL語句時都要進行SQL語句的解析和編譯操作,效率低。

PreparedStatement更安全,批處理效率高

     PreparedStatement使用預處理編譯,批處理比Statement效率高,傳入的任何引數都不會和已經編譯的SQL語句進行拼接,避免了SQL注入攻擊問題。

索引以及索引的實現(B+樹介紹,和B樹、R樹的區別)

     B樹是為磁碟或其他直接儲存輔助儲存裝置而設計的一種平衡二叉查詢樹,B樹與紅黑樹類似,但在降低磁碟I/O操作次數方面要更好一些,資料庫就是通常用B樹來進行儲存資訊。開始瞭解B~tree之前,先了解下相關的硬體知識,才能很好的瞭解為什麼需要B~tree這種外存資料結構。

    所以,在大規模資料儲存方面,大量資料儲存在外存磁碟中,而在外存磁碟中讀取/寫入塊(block)中某資料時,首先需要定位到磁碟中的某塊,如何有效地查詢磁碟中的資料,需要一種合理高效的外存資料結構,就是下面所要重點闡述的B-tree結構,以及相關的變種結構:B+-tree結構和B*tree結構(B+樹的升級版)

B樹:

B+樹:

B*樹:

為什麼說B+-tree比B 樹更適合實際應用中作業系統的檔案索引和資料庫索引?

★ B+-tree的磁碟讀寫代價更低

    B+-tree的內部結點並沒有指向關鍵字具體資訊的指標。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入記憶體中的需要查詢的關鍵字也就越多。相對來說IO讀寫次數也就降低了。舉個例子,假設磁碟中的一個盤塊容納16bytes,而一個關鍵字2bytes,一個關鍵字具體資訊指標2bytes。一棵9階B-tree(一個結點最多8個關鍵字)的內部結點需要2個盤快。而B+ 樹內部結點只需要1個盤快。當需要把內部結點讀入記憶體中的時候,B 樹就比B+ 樹多一次盤塊查詢時間(在磁碟中就是碟片旋轉的時間)。

B+-tree的查詢效率更加穩定

     由於非終結點並不是最終指向檔案內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查詢必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。

什麼是資料庫連線池

     建立資料庫連線是一個很耗時的操作,也容易對資料庫造成安全隱患。所以,在程式初始化的時候,集中建立多個數據庫連線,並把他們集中管理,供程式使用,可以保證較快的資料庫讀寫速度,還更加安全可靠。建立連線池,可以減少物件初始化、建立的時間,這個和執行緒池有點類似。都是為了節省建立時間,資源複用。

     剛接觸JDBC時,都是通過DriverManager.getConnection這個介面方法來獲得連線物件Connection。但是每次都通過這種方式來獲得資料庫連線物件很麻煩也很耗費資源。每次需要連線物件的時候,都要花費時間通過這個方法去獲得資料庫連線物件,很耗費時間。 怎麼優化獲得資料庫連線物件使耗時更短?

     使用資料庫連線池:就是在連線資料庫前,事先用幾個資料庫連線物件變數去和資料庫進行連線好(一直連線,不斷開),在池子中一直等待,當要使用資料庫連線物件的時候,直接到池子中把已經提前連線好的物件拿來用,然後用完之後再把物件還回池子裡面去。如果池子中有3個事先連線好的資料庫連線物件,但是一次把三個物件都拿去用了,那麼下一個使用者過來要使用資料庫連線物件的時候,就要等待了,等待前面的用完把物件還回到池子中,然後再去拿來使用。連線池的目的就是提前準備多個已經連線到了資料庫的物件在那裡準備著被拿去使用,當你要使用的時,直接從池子裡拿出來用,用完之後再給人家放回去,用來優化資料庫連線。

    資料庫連線池使用過程分為四步:程式初始化時建立連線池→使用時向連線池申請可用連線→使用完畢,將連線返還給連線池→ 程式退出時,斷開所有連線,並釋放資源。

    Sun公司並沒有做資料庫連線池的實現,它只是做了一個規範,也不給出具體的資料庫連線池的概念,而是做了一個數據源javax.sql.DataSource,這個資料庫源只是資料庫連線的一個優化手段的規範的介面,至於你具體怎麼去實現這個資料庫連線池由自己定義。或者你自己不想使用資料庫連線池這個方法也可以,你只要在這個地方能夠以很優化的方式給我提供資料庫連線物件就行了。

連線池框架:

C3P0 比較耗費資源,效率方面可能要低一點。 ★ DBCP 在實踐中存在BUG,在某些種情會產生很多空連線不能釋放,Hibernate3.0已經放棄了對其的支援。 ★ Proxool 的負面評價較少,現在比較推薦它,而且它還提供即時監控連線池狀態的功能,便於發現連線洩漏的情況。

Druid  阿里出品,淘寶和支付寶專用資料庫連線池,它結合了C3P0、DBCP、PROXOOL等DB池的優點,同時加入了日誌監控,可以很好的監控DB池連線和SQL的執行情況,可以說是針對監控而生的DB連線池。但它不僅僅是一個數據庫連線池,它還包含一個ProxyDriver,一系列內建的JDBC元件庫,一個SQL Parser。支援所有JDBC相容的資料庫,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。Druid針對Oracle和MySql做了特別優化,比如Oracle的PS Cache記憶體佔用優化,MySql的ping檢測優化。Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支援,這是一個手寫的高效能SQL Parser,支援Visitor模式,使得分析SQL的抽象語法樹很方便。