上一篇博客,主要是簡單的介紹了普通數據庫連接的過程以及耗費的資源,並且簡單的談了下連接池,這篇我們主要來看看數據庫連接池的使用以及它最優的配置。
總目錄:
-1.數據庫連接過程是怎樣的?
-2.連接所占用的資源有哪些?
-3.連接池簡介
-4.連接池的使用
-5.最優連接池配置選擇
今天主要看看4和5。
這裡我使用的是c3p0數據庫連接池
簡單的介紹一下c3p0:C3P0是一個開源的JDBC連接池,它實現了數據源和JNDI綁定,支持JDBC3規范和JDBC2的標准擴展。目前使用它的開源項目有Hibernate,Spring等。
連接池的種類也有很多,而且每種也有不同的適用場景,所以選擇適合自己的連接池也是一方面~
先放不使用連接池和使用連接池的數據對比。
循環連接10次,圖片為測試的第10組數據。
不使用連接池
使用連接池
紅色為連接池部分配置信息
從圖片我們可以明顯的看出,連接池的速度要快於普通連接很多,這裡很多不是指的二者差多少毫秒,而是倍數的差別。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPC9ibG9ja3F1b3RlPgoKPGhyPgoKPGgzIGlkPQ=="java連接池代碼">java連接池代碼:
import com.mchange.v2.c3p0.ComboPooledDataSource; import java.awt.color.ProfileDataException; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ResourceBundle; /** * Created by wwh on 15-6-10. */ public class DBPollClass { private static DBPollClass dbPoll; private ComboPooledDataSource dbSource; //靜態代碼塊,一開始我們就執行構造函數加載配置信息 static { dbPoll = new DBPollClass(); } public DBPollClass(){ //設置配置信息 try{ dbSource = new ComboPooledDataSource(); dbSource.setUser("root"); dbSource.setPassword("123456789"); dbSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/XL_db?user=root&password=123456789&useUnicode=true"); dbSource.setDriverClass("com.mysql.jdbc.Driver"); dbSource.setInitialPoolSize(1); dbSource.setMinPoolSize(2); dbSource.setMaxPoolSize(10); dbSource.setMaxStatements(50); dbSource.setMaxIdleTime(60); }catch (PropertyVetoException e){ throw new RuntimeException(e); } } //獲得連接 public final static DBPollClass getInstance(){ return dbPoll; } public final Connection getConnection(){ try{ return dbSource.getConnection(); }catch (SQLException e){ throw new RuntimeException("無法獲取連接", e); } } public static void main(String[] args) throws SQLException { for(int i = 0; i < 10; i++) { long begintime = System.currentTimeMillis(); Connection con = null; try { //取得空閒連接 con = dbPoll.getInstance().getConnection(); //執行sql語句並返回查詢結果 //ResultSet rs = con.createStatement().executeQuery("SELECT * from UserInfo"); //使用PreparedStatement而不使用Statement PreparedStatement pst = con.prepareStatement("SELECT * from UserInfo"); ResultSet rs = pst.executeQuery(); //輸出查詢結果 while (rs.next()) { System.out.println(rs.getObject(1) + " " + rs.getObject(2) + " " + rs.getObject(3) + " " + rs.getObject(4)); } } catch (Exception e) { e.printStackTrace(); } finally { if (con != null) { //歸還空閒連接 con.close(); } } long endtime = System.currentTimeMillis(); System.out.println((i+1) + " time is:" + (endtime-begintime)); } } }
從代碼我們可以和清晰的看出連接池的使用是非常簡單的,代碼中我將連接池的配置等信息寫到了構造函數中,其實現實中使用我們一般寫在c3p0-config.xml,數據庫連接池的配置文件中,然後放到src目錄下即可。
連接池的使用步驟和普通的JDBC連接數據庫基本一樣。參數也類似
只不過部分含義不同,連接池的connection,並不是創建連接,而是從數據庫連接池中間找出一個空閒的連接,con.close()也不是斷開連接,而是歸還給連接池。
還有注意我們不僅僅要歸還connection資源,還要歸還Preparedstatement和ResultSet的資源
我們也需要養成良好的習慣使用Preparedstatement而不是statement,因為Preparedstatement裡面包含了部分已經編譯好的sql語句,可以提高執行速度。
5.最優連接池配置選擇
使用和使用好兩個詞是截然不同的,我們的目的不僅僅是使用線程池或者數據庫連接池,而是通過使用它們來發揮服務器最大威力以及效率達到最優。
這就要我們根據自己服務器配置信息來選擇參數了~。
先看看代碼中我們設定了哪些參數。設置初始化連接池大小
dbSource.setInitialPoolSize(1);設置連接池內最小連接數
dbSource.setMinPoolSize(2);設置連接池內最大連接數
dbSource.setMaxPoolSize(10);用來控制Preparedstatement的數量
dbSource.setMaxStatements(50);最大空閒時間,60秒內未使用連接則被丟取,設置為0則永不丟棄
dbSource.setMaxIdleTime(60);
以上為常用和關鍵的參數。
關於最關鍵的參數設定
1.最小連接數
連接池一直保持的數據庫連接。最小連接數的大小我們要根據實際的使用情況不斷的測試來決定,如果設定大了就會有許多空閒的連接,浪費了資源。2.最大連接數
連接池的連接上限,一般當連接值大於最小連接數時,連接池就會創建新的connection來接受連接,我們設定的超時時間就是針對新創建的連接的,當使用完最小連接數外的連接時,它們不會被立即釋放,而是停留MaxIdleTime時間,如果在MaxIdleTime時間沒有再次被連接,則釋放。如果超過最大連接數,那麼新到的連接會被加入到等待隊列中。3.最大空閒時間MaxIdleTime,這個要根據實際情況來調整設定了。
如果最小連接數和最大連接數相差很大,那麼最先到的連接最獲利,連接速度非常快,後到的會稍微慢點,因為要創建連接。
我們一般設定池的大小時,比如線程池,首先要確定是CPU密集型還是IO密集型,如果是CPU密集型,那麼我們如果線程池設定應該和CPU核數幾乎一致,因為此時大量的計算,如果線程數量設定過大,那麼線程切換消耗的時間就是主要花費,如果是IO密集型,那麼線程數量要大於CPU數量,因為線程可能阻塞在IO處,所以阻塞時要切換其他線程繼續執行,效率會高。
那麼訪問數據庫是IO密集型的,因為內部也是創建單獨的線程來連接,所以類似線程池,線程池IO密集型線程數計算公式為:
線程數 = CPU核數 / (1-阻塞系數),阻塞系數也應該根據我們具體情況來分析。
一般線程數為核心數的幾倍。
我就簡單的介紹到這裡,上面所說也是根據自己現有的知識和查詢的資料來描述的,並不一定全部正確,希望大家帶著審視的眼光來看,如果哪部分錯了,還望指出,謝謝~