在使用開發基于資料庫的web程式時,傳統的模式基本是按以下步驟:
在主程式(如servlet、beans)中建立資料庫連接配接。
進行sql操作
斷開資料庫連接配接。
這種模式開發,存在的問題:
普通的JDBC資料庫連接配接使用 DriverManager 來擷取,每次向資料庫建立連接配接的時候都要将 Connection 加載到記憶體中,再驗證使用者名和密碼(得花費0.05s~1s的時間)。需要資料庫連接配接的時候,就向資料庫要求一個,執行完成後再斷開連接配接。這樣的方式将會消耗大量的資源和時間。資料庫的連接配接資源并沒有得到很好的重複利用.若同時有幾百人甚至幾千人線上,頻繁的進行資料庫連接配接操作将占用很多的系統資源,嚴重的甚至會造成伺服器的崩潰。
對于每一次資料庫連接配接,使用完後都得斷開。否則,如果程式出現異常而未能關閉,将會導緻資料庫系統中的記憶體洩漏,最終将導緻重新開機資料庫。
這種開發不能控制被建立的連接配接對象數,系統資源會被毫無顧及的配置設定出去,如連接配接過多,也可能導緻記憶體洩漏,伺服器崩潰.
2.資料庫連接配接池(connection pool)
為解決傳統開發中的資料庫連接配接問題,可以采用資料庫連接配接池技術。
資料庫連接配接池的基本思想就是為資料庫連接配接建立一個“緩沖池”。預先在緩沖池中放入一定數量的連接配接,當需要建立資料庫連接配接時,隻需從“緩沖池”中取出一個,使用完畢之後再放回去。
資料庫連接配接池負責配置設定、管理和釋放資料庫連接配接,它允許應用程式重複使用一個現有的資料庫連接配接,而不是重建立立一個。
資料庫連接配接池在初始化時将建立一定數量的資料庫連接配接放到連接配接池中,這些資料庫連接配接的數量是由最小資料庫連接配接數來設定的。無論這些資料庫連接配接是否被使用,連接配接池都将一直保證至少擁有這麼多的連接配接數量。連接配接池的最大資料庫連接配接數量限定了這個連接配接池能占有的最大連接配接數,當應用程式向連接配接池請求的連接配接數超過最大連接配接數量時,這些請求将被加入到等待隊列中。
3.資料庫連接配接池技術的優點
(1)資源重用:由于資料庫連接配接得以重用,避免了頻繁建立,釋放連接配接引起的大量性能開銷。在減少系統消耗的基礎上,另一方面也增加了系統運作環境的平穩性。
(2)更快的系統反應速度:資料庫連接配接池在初始化過程中,往往已經建立了若幹資料庫連接配接置于連接配接池中備用。此時連接配接的初始化工作均已完成。對于業務請求處理而言,直接利用現有可用連接配接避免了資料庫連接配接初始化和釋放過程的時間開銷,進而減少了系統的響應時間
(3)新的資源配置設定手段對于多應用共享同一資料庫的系統而言,可在應用層通過資料庫連接配接池的配置實作某一應用最大可用資料庫連接配接數的限制避免某一應用獨占所有的資料庫資源.
(4)統一的連接配接管理,避免資料庫連接配接洩露在較為完善的資料庫連接配接池實作中,可根據預先的占用逾時設定,強制回收被占用連接配接,進而避免了正常資料庫連接配接操作中可能出現的資源洩露。
下面我就來介紹如何簡單使用c3p0連接配接池
(1)配置檔案,位于src下的c3p0-config.xml,檔案名為c3p0-config,會自動讀取。各項配置具體解釋自行上網搜尋
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="user">root</property>
<property name="password"></property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
</c3p0-config>
(2)連接配接工具類
package com.myc3p0.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DBConn {
private static ComboPooledDataSource ds = new ComboPooledDataSource();
// 取得連接配接
public static Connection getConn() {
try {
return ds.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 關閉連結,其實是将連接配接回收
public static void close(Connection conn) throws SQLException {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw e;
}
}
}
public static void close(PreparedStatement pstate) throws SQLException {
if (pstate != null) {
pstate.close();
}
}
public static void close(ResultSet rs) throws SQLException {
if (rs != null) {
rs.close();
}
}
}
(3)測試
package com.myc3p0.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestC3P0 {
public static void main(String[] args) {
Connection conn = DBConn.getConn();
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "select * from temp where id = 1";
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
Student student = new Student();
while(rs.next()){
student.setId(rs.getInt(1));
student.setName(rs.getString(2));
}
System.out.println(student);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//關閉連接配接,其實是将連接配接回收
DBConn.close(rs);
DBConn.close(pstmt);
DBConn.close(conn);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}