數據庫學習筆記二十三 —— 數據庫連接池(DBCP、C3P0)
數據庫連接池簡介
數據庫連接—>執行完畢—>釋放,其中連接—>釋放十分浪費系統資源
池化技術: 準備一些預先的資源,過來就連接預先準備好的
比如銀行,開門—>服務—>關門,如果每一個客戶都這樣的話浪費時間,所以開門後準備業務員服務,這樣就不用每一次都執行多餘的步驟了。開門—>業務員:等待客戶—>服務—>關門。那一個銀行最少需要多少個服務員呢?這就涉及到 最小連接數 ,最大連接數就是業務最高承載上限,如果銀行的客戶很多,那麼客戶需要等待時間,這就是等待超時
例如:
最小連接數 10個(通常爲你常用的連接數)
最大連接數 15個
等待超時 100ms
實現簡介
編寫連接池,需要實現一個接口 DataSource
- 開源數據源實現
- DBCP
- C3P0
- Druid:阿里巴巴
使用了這些數據庫連接池後,我們在項目開發中就不需要編寫連接數據庫的代碼了
DBCP
需要用到的jar包
1.commons-dbcp 下載地址 http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi
選擇好版本後點擊下載
解壓後用到這個文件
2.commons-pool 下載地址 http://commons.apache.org/proper/commons-pool/download_pool.cgi 下載方法同上,
用到的jar包是這個
把這兩個包粘貼到你idea項目的lib目錄下,如果你第一次導包就右擊lib目錄,選擇下圖選中的。
如果你的idea是版本比較新的,以前這個lib目錄Add as Library過了的話,直接粘貼進去就行了,
如果版本比較舊的話,可能需要如下圖刪除原來的Library裏的lib,然後再重新add一遍
右上角點擊項目結構,或者在左上角的File裏也有
打開後進行如下操作,然後再次將你的lib目錄右擊Add as Library
最後,總之只要你的lib目錄裏的jar包能如圖顯示分層,就能用了
代碼相關
在src下新建一個DBCP的配置文件dbcpconfig.properties(新建File,命名加後綴爲就行)
#連接設置 (這裏面的變量名,是DBCP數據源中定義好的,不要自己起名字)
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456
# 下面的全都可以不設置,不寫
#<!-- 初始化連接 -->
initialSize=10
#最大連接量
maxActive=50
#<!-- 最大空閒連接 --> 沒人用也空着不釋放,等超時之後再釋放
maxIdle=20
#<!-- 最小空閒連接 -->
minIdle=5
#<!-- 超時等待時間,以毫秒爲單位 60000/1000 = 60秒 -->
maxWait=60000
#JDBC驅動建立連接時附帶的連接屬性的格式必須爲這樣:[屬性名=property;]
#注意:"user"與"password"連個屬性會被明確傳遞,因此這裏不需要包含他們
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由連接池所創建的連接的自動提交(auto-commit)狀態。
defaultAutoCommit=true
#driver default 指定由連接池所創建的連接的只讀(read-only) 狀態。
#如果沒有設置該值,則"setReadOnly"方法將不被調用。(某些驅動並不支持只讀模式,如: Informix)
defaultReadOnly=
#driver default 指定由連接池所創建的連接的事務級別(TransactionIsolation)。
#可用值爲下列之一: (詳情可見javadoc)NONE,READ_ UNCOMMITTED,READ_ COMMITTED,REPEATABLE_ READ等
defaultTransactionIsolation=READ_UNCOMMITTED
自己封裝一個工具類 JdbcUtils_DBCP
package pers.ylw.lesson05.utils;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static BasicDataSource dataSource = null;
static {
try{
//通過反射獲取配置文件資源流
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//創建數據源 工廠模式-->創建對象
dataSource = BasicDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
//獲取連接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //從數據源中獲取連接
}
//釋放連接資源
public static void release(Connection conn, Statement st,ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用這個 JdbcUtils_DBCP 工具類進行操作
package pers.ylw.lesson05;
import pers.ylw.lesson05.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
public class TestDBCP {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils_DBCP.getConnection(); //只是改了這一行和最後關閉資源的時候,使用的類,其他的和前面的筆記沒有區別
//注意PreparedStatement與Statement的區別
//書寫SQL語句,使用?佔位符代替參數
String sql = "insert into users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) values (?,?,?,?,?)";
st = conn.prepareStatement(sql);//預編譯sql,先寫sql,然後不執行
//手動給參數賦值,第一個參數是?的下標(從1開始),第二個參數是?的值
st.setInt(1,4);
st.setString(2,"ylw");
st.setString(3,"123456");
st.setString(4,"[email protected]");
//注意時間轉換,sql.Date數據庫時間,util.Date Java時間,new Date().getTime()獲得時間戳
st.setDate(5,new java.sql.Date(new Date().getTime()));
//執行
int i = st.executeUpdate();
if (i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils_DBCP.release(conn,st,null); //關資源
}
}
}
如果你使用的包版本比較新可能會出現異常:
用DBCP進行數據連接池連接的時候出現java.lang.NoClassDefFoundError: Could not initialize class xxx.xxx.util.JdbcUtils_DBCP異常
解決方案:導入commanns-logging包
下載地址 https://commons.apache.org/proper/commons-logging/download_logging.cgi
C3P0
需要用到的jar包
1.c3p0 下載地址 https://sourceforge.net/projects/c3p0/
點擊下載,你得等一會他才下載
包在lib文件夾裏
2.mchange-commons-java
下載地址 https://mvnrepository.com/artifact/com.mchange/mchange-commons-java
推薦倒數第二新版本
點擊jar進行下載
導包在上面DBCP中講的很詳細了
代碼相關
在src下新建一個c3p0的配置文件c3p0-config.xml(新建File,命名加後綴爲就行)
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<!--c3p0的缺省(默認)配置
如果在代碼中"ComboPooledDataSource ds = new ComboPooledDataSource();"這樣寫就表示使用的是C3P0的缺省(默認)配置
-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!--改成你自己的url-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false</property>
<!--改成你自己的用戶名-->
<property name="user">root</property>
<!--改成你自己的密碼-->
<property name="password">123456</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!--
C3P0的命名配置,
如果在代碼中"ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");"這樣寫就表示使用的是name是MySQL
-->
<named-config name="MySQL">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!--改成你自己的url-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false</property>
<!--改成你自己的用戶名-->
<property name="user">root</property>
<!--改成你自己的密碼-->
<property name="password">123456</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
自己封裝一個工具類 JdbcUtils_C3P0
package pers.ylw.lesson05.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils_C3P0 {
private static ComboPooledDataSource dataSource = null;
static {
try{
//代碼版配置,不寫在配置文件裏
// dataSource = new ComboPooledDataSource();
// dataSource.setDriverClass();
// dataSource.setUser();
// dataSource.setPassword();
// dataSource.setJdbcUrl();
//
// dataSource.setMaxPoolSize();
// dataSource.setMinPoolSize();
//c3p0的配置文件不需要向DBCP那樣獲取,可以自動加載
//創建數據源 工廠模式-->創建對象
dataSource = new ComboPooledDataSource("MySQL");//配置文件寫法
}catch (Exception e){
e.printStackTrace();
}
}
//獲取連接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //從數據源中獲取連接
}
//釋放連接資源
public static void release(Connection conn, Statement st,ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用這個 JdbcUtils_C3P0 工具類進行操作
package pers.ylw.lesson05;
import pers.ylw.lesson05.utils.JdbcUtils_C3P0;
import pers.ylw.lesson05.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
public class TestC3P0 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils_C3P0.getConnection(); //只是改了這一行和最後關閉資源的時候,使用的類,其他的前面的筆記沒有區別
//注意PreparedStatement與Statement的區別
//書寫SQL語句,使用?佔位符代替參數
String sql = "insert into users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) values (?,?,?,?,?)";
st = conn.prepareStatement(sql);//預編譯sql,先寫sql,然後不執行
//手動給參數賦值,第一個參數是?的下標(從1開始),第二個參數是?的值
st.setInt(1,4);
st.setString(2,"ylw");
st.setString(3,"123456");
st.setString(4,"[email protected]");
//注意時間轉換,sql.Date數據庫時間,util.Date Java時間,new Date().getTime()獲得時間戳
st.setDate(5,new java.sql.Date(new Date().getTime()));
//執行
int i = st.executeUpdate();
if (i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils_C3P0.release(conn,st,null); //關資源
}
}
}
C3P0運行成功還會顯示配置文件
總結
無論使用什麼數據,本質還是一樣的,DateSource接口不會變,方法就不會變