在使用開發基於數據庫的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();
}
}
}
