資料庫連線池DataSource
什麼是資料庫連線池
資料庫連線是一種關鍵的有限的昂貴的資源,這一點在多使用者的網頁應用程式中體現得尤為突出。對資料庫連線的管理能顯著影響到整個應用程式的伸縮性和健壯性,影響到程式的效能指標。資料庫連線池正是針對這個問題提出來的。資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。這項技術能明顯提高對資料庫操作的效能。
以下是使用連線池與沒有使用連線池的一個比較圖例
連線池的優點
節省建立連線與釋放連線效能消耗連線池中連線起到複用的作用
其實使用連線池的時候,也是有點缺點的:
在程式最開始的時候必須載入連線池物件,所以肯定會消耗較多的資源,但是也比每次都建立連線消耗資源強。
連線池的原理
連線池基本的思想是在系統初始化的時候,將資料庫連線作為物件儲存在記憶體中,當用戶需要訪問資料庫時,並非建立一個新的連線,而是從連線池中取出一個已建立的空閒連線物件。使用完畢後,使用者也並非將連線關閉,而是將連線放回連線池中,以供下一個請求訪問使用。而連線的建立、斷開都由連線池自身來管理。同時,還可以通過設定連線池的引數來控制連線池中的初始連線數、連線的上下限數以及每個連線的最大使用次數、最大空閒時間等等。也可以通過其自身的管理機制來監視資料庫連線的數量、使用情況等。
用通俗的話來說就是:弄一個集合,扔幾個連線物件到集合(連線池)中,當用戶需要獲取連線時,從集合(連線池)中取出一個,使用完後再重新放回集合(連線池)中,以供下一次再使用,也就是連線池中的物件是可以重複使用的。
在瞭解了連線池實現的原始碼後我試著模擬寫一個簡單版的連線池大概實現原理
public class MyDataSource {
private LinkedList<Connection> ll;
public MyDataSource() throws SQLException {
ll = new LinkedList<Connection>();
//當建立MyDataSource時就會向集合中新增10個Connection物件。
for (int i = 0; i < 10; i++) {
//使用自己封裝的JdbcUtils工具類獲取一個連線物件
ll.add(JdbcUtils.getConnection());
}
}
// 獲取連線,將集合中的connection返回一個
public Connection getConnection() {
return ll.removeLast();
}
// 關閉連線,將連線物件重新再放回集合中去
public void closeConnection(Connection con) {
ll.addFirst(con);
}
}
下面是使用上面自己建立的資料庫連線池
public class DataSourceDemo1 {
public static void main(String[] args) throws SQLException {
String sql = "select * from account";
// 建立一個連線池
MyDataSource mds = new MyDataSource();
// 從連線池中獲取一個連線物件
Connection con = mds.getConnection();
ResultSet rs = con.prepareStatement(sql).executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id") + " "
+ rs.getString("username") + " " + rs.getString("money"));
}
rs.close();
//mds.closeConnection(con);//將連線物件重新放回到池中。
con.close();
}
}
連線池規定
javax.sql包下有一個 DataSource
所有的支援java的連線池都應該實現javax.sql.DataSource介面,在這個介面中提供了一個方法 getConnection()它就是獲取一個連線物件的。
如果連線物件Connection是通過連線池獲取的,當通過Connection物件呼叫close()方法時,不再是銷燬連線物件,而是將連線物件放回到連線池。所以Connection物件呼叫close()方法時,具體做什麼操作需要看這個Connection物件是怎麼來的。
1,如果就是普通獲取(驅動管理器DriverManager),那麼close()就是關閉連線。
2,如果是通過連線池(DataSource)獲取,那麼close()就是將連線物件重新放回連線池中。
具體實現方式是使用了動態代理在實現了DataSource介面後對父類Connection的方法進行了重寫。
畢竟在開發中,資料庫連線池不會讓我們去實現,瞭解了資料庫連線池的大概原理後,讓我們來看看常用的資料庫連線池有哪些以及在開發如何使用。
連線池的使用在專案中一般可以分為兩種,一種是直接在java程式碼中以編碼的方式實現,另一種則是通過載入配置檔案的方式。
Dbcp連線池(瞭解)
DBCP 是 Apache 軟體基金組織下的開源連線池實現,使用DBCP資料來源,應用程式應在系統中增加如下兩個 jar 檔案:
Commons-dbcp.jar:連線池的實現
Commons-pool.jar:連線池實現的依賴庫
Tomcat 的連線池正是採用該連線池來實現的。該資料庫連線池既可以與應用伺服器整合使用,也可由應用程式獨立使用。DBCP 是 Apache 軟體基金組織下的開源連線池實現,使用DBCP資料來源,應用程式應在系統中增加如下兩個 jar 檔案:
Commons-dbcp.jar:連線池的實現
Commons-pool.jar:連線池實現的依賴庫
Tomcat 的連線池正是採用該連線池來實現的。該資料庫連線池既可以與應用伺服器整合使用,也可由應用程式獨立使用。
dbcp連線池編碼實現
// 1.建立連線池物件
BasicDataSource ds = new BasicDataSource();
// 2.設定相關屬性
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///day13");
ds.setUsername("root");
ds.setPassword("abc");
dbcp連線池配置檔案實現
//1.載入配置資訊
Properties props = new Properties();//建立了一個map集合
props.load(new FileInputStream(properties配置檔案路徑);
properties檔案內容
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///資料庫名
username=root
password=root
// 2.通過BasicDataSourceFactory獲取一個連線池物件
DataSource ds = BasicDataSourceFactory.createDataSource(props);
C3p0連線池
C3P0是一個開源的JDBC連線池,它實現了資料來源和JNDI繫結,支援JDBC3規範和JDBC2的標準擴充套件。目前使用它的開源專案有Hibernate,Spring等。
c3p0與dbcp區別
dbcp沒有自動回收空閒連線的功能
c3p0有自動回收空閒連線功能
在使用c3p0連線池時將c3p0的jar 複製WEB-INF/lib下,我們使用的版本
c3p0-0.9.1.2.jar
c3p0連線池編碼實現
ComboPooledDataSource ds = new ComboPooledDataSource();
// 2.手動配置引數
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///day13");
ds.setUser("root");
ds.setPassword("abc");
c3p0連線池配置檔案實現如果配置檔名稱是 c3p0.properties或c3p0-config.xml
那麼c3p0就會預設在classpath根目錄下查詢這個配置檔案。
只要在src下建立c3p0.properties or c3p0-config.xml名稱的配置檔案,c3p0會自動查詢.
ComboPooledDataSource ds = new ComboPooledDataSource();
自動查詢配置檔案
在src/c3p0-config.xml
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///資料庫名</property>
<property name="user">root</property>
<property name="password">abc</property>
</default-config>
</c3p0-config>
連線池的工具類
public class DataSourceUtils {
private static ComboPooledDataSource cpds = new ComboPooledDataSource();//自動去載入c3p0-config.xml配置檔案讀取資料庫連線相關資訊
//獲取連線物件,從連線池中返回一個連線物件
public static Connection getConnection() throws SQLException {
return cpds.getConnection();
}
//獲取連線池物件
public static DataSource getDataSource() {
return cpds;
}
}