早期我們怎么進行數據庫操作呢?
1、原理:一般來說,Java應用程序訪問數據庫的過程是:
- 加載數據庫驅動程序;
- 通過jdbc建立數據庫連接;
- 訪問數據庫,執行SQL語句;
- 斷開數據庫連接。
2、代碼
1 //查詢所有用戶
2 Public void FindAllUsers(){ 3 //1、裝載sqlserver驅動對象
4 DriverManager.registerDriver(new SQLServerDriver()); 5 //2、通過JDBC建立數據庫連接
6 Connection con = DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer","sa","123"); 7 //3、創建狀態
8 Statement state = con.createStatement(); 9 //4、查詢數據庫並返回結果
10 ResultSet result = state.executeQuery("select * from users"); 11 //5、輸出查詢結果
12 while(result.next()){ 13 System.out.println(result.getString("email")); 14 } 15 //6、斷開數據庫連接
16 result.close(); 17 state.close(); 18 con.close(); 19 }
3、分析
程序開發過程中,存在很多問題:
首先,每一次web請求都要建立一次數據庫連接。建立連接是一個費時的活動,每次都得花費0.05s~1s的時間,而且系統還要分配內存資源。這個時間對於一次或幾次數據庫操作,或許感覺不出系統有多大的開銷。可是對於現在的web應用,尤其是大型電子商務網站,同時有幾百人甚至上千人在線是很正常的事。在這種情況下,頻繁的進行數據庫連接操作勢必占用很多的系統資源,網站的響應速度必定下降,嚴重的甚至會造成服務器的崩潰。不是危言聳聽,這就是制約某些電子商務網站發展的技術瓶頸問題。
其次,對於每一次數據庫連接,使用完后都得斷開。否則,如果程序出現異常而未能關閉,將會導致數據庫系統中的內存泄露,最終將不得不重啟數據庫。還有,這種開發不能控制被創建的連接對象數,系統資源會被毫無顧忌的分配出去,如連接過多,也可能導致內存泄漏,服務器崩潰。
通過上面的分析,我們可以看出,“數據庫連接”是一種稀缺的資源,為了保障網站的正常使用,應該對其進行妥善管理,其實我們查詢玩數據庫后,如果不關閉連接,而是暫時存放起來,當別人使用時,把這個連接給他們使用。就避免了一次建立數據庫鏈接和斷開的操作時間消耗。原理如下:
技術演進出來的數據庫連接池
由上面的分析可以看出,問題的根源就在於對數據庫連接資源的低效管理。我們知道,對於共享資源,有一個著名的設計模式:資源池設計模式。該模式正是為了解決資源的頻繁分配、釋放所造成的問題。為解決上述問題,可以采用數據庫連接池技術。數據庫連接池的基本系思想就是為數據庫連接建立一個“緩沖池”。預先在緩沖池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩沖池”中取出一個,使用完畢之后再放回去。我們可以通過設定連接池最大連接數來防止系統無盡地與數據庫連接。更為重要的是我們可以通過連接池的管理機制監視數據庫的連接的數量、使用情況,為系統開發、測試及性能調整提供依據。
我們自己嘗試開發一個連接池,來為上面的查詢業務提供數據庫連接服務:
1)編寫class實現DataSource接口;
2)在class的構造器一次性創建10個連接,將連接保存在LinkedList中;
3)實現getConnection,從LinkedList中返回一個連接;
4)提供將連接放回連接池中的方法;
1、連接池代碼
1 Pubic class MyDataSource implements DataSource{ 2 //因為LinkedList是用鏈表實現的,對於增刪實現起來比較容易
3 LinkedList<Connection> dataSources = new LinkedList<Connection>(); 4 //初始化連接數量
5 public MyDataSource(){ 6 //問題:每次new MyDataSource都會建立10個連接,可使用單例設計模式解決此問題。
7 for(int i=0;i<10;i++){ 8 try{ 9 //1、裝載sqlserver驅動對象
10 DriverManager.registerDriver(new SQLServerDriver()) 11 //2、通過JDBC建立數據庫連接
12 Connection con =DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer","sa","123"); 13 //3、將連接加入連接池中
14 dataSources.add(con); 15 }catch(Exception e){ 16 e.printStackTrace(); 17 } 18 } 19 } 20 public Connection getConnection() throws SQLException{ 21 //取出連接池中一個連接
22 final Connection conn = dataSources.removeFirst();//刪除第一個連接返回
23 return conn; 24 } 25 //將連接放回連接池
26 public void releaseConnection(Connection conn){ 27 dataSources.add(conn); 28 } 29 }
2、使用連接池重構我們的用戶查詢函數
1 //查詢所有用戶
2 Public void FindAllUsers(){ 3 //1、使用連接池建立數據庫連接
4 MyDataSources dataSources = new MyDataSources(); 5 Connection conn = dataSources.getConnection(); 6 //2、創建狀態
7 Statement state = con.createStatement(); 8 //3、查詢數據庫並返回結果
9 ResultSet result =state.executeQuery("select * from users"); 10 //4、輸出查詢結果
11 while(result.next()){ 12 System.out.println(result.getString("email")); 13 } 14 //5、斷開數據庫連接
15 result.close(); 16 state.close(); 17 //6、歸還數據庫鏈接給連接池
18 dataSources.releaseConnection(conn); 19 }
連接池的工作原理:
連接池的核心思想是連接的復用,通過建立一個數據庫連接池以及一套連接使用、分配和管理策略,使得該連接池中的連接可以得到高效、安全的復用,避免了數據庫連接頻繁簡歷和關閉的開銷。
連接池的工作原理主要由三部分組成,分別為連接池的建立,連接池中連接的使用管理,連接池的關閉。
第一、連接池的建立。一般在系統初始化時,連接池會根據系統配置建立,並在池中建立幾個連接對象,以便使用時能從連接池中獲取。Java中提供了很多容器類,可以方便的構建連接池,例如Vector(線程安全類)、linkedlist等。
第二、連接池的管理。連接池管理策略是連接池機制的核心,連接池內連接的分配和釋放對系統的性能有很大的影響。其策略是:
當客戶請求數據庫鏈接時,首先查看連接池中是否有空閑連接,如果存在空閑連接,則將連接分配給用戶使用並作相應處理(即標記該連接為正在使用,引用計數加1);如果沒有空閑連接,則查看當前所開的連接數是否已經達到最大連接數,如果沒有達到最大連接數,就重新創建一個連接給請求的用戶;如果達到,就按設定的最大等待時間進行等待,如果超出最大等待時間,則拋出異常給客戶。
當客戶釋放數據庫連接時,先判斷該連接的引用次數是否超過了規定值,如果超過了就從連接池中刪除該鏈接,並判斷當前連接池內總的連接數是否小於最小連接數,若小於就將連接池充滿;如果沒超過就將該連接標記為開放狀態,可供再次復用。
第三、連接池的關閉。當應用程序退出時,關閉連接池中所有的連接,釋放連接池相關資源,該過程正好與創建相反。
連接池的主要優點:
1)減少連接的創建時間。連接池中的連接是已准備好的,可以重復使用的,獲取后可以直接訪問數據庫,因此減少了連接創建的次數和時間。
2)更快的系統響應速度。數據庫連接池在初始化過程中,往往已經創建了若干個數據庫連接置於池中備用。此時連接的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連接,避免了數據庫連接初始化和釋放過程的時間開銷,從而縮減了系統整體響應時間。
3)統一的連接管理。如果不使用連接池,每次訪問數據庫都需要創建一個連接,這樣系統的穩定性受系統的連接需求影響很大,很容易產生資源浪費和高負載異常。連接池能夠使性能最大化,將資源利用控制在一定的水平之下。連接池能控制池中的連接數量,增強了系統在大量用戶應用時的穩定性。
