數據庫連接池基本介紹
文章目錄
1. 基本概念
數據庫連接池的本質上是一個容器(集合),存放數據庫連接的容器,當系統初始化好後,容器被創建,容器中會申請一些連接對象,當用戶來訪問數據庫時,從容器中獲取連接對象,用戶訪問完後,會將連接對象歸還給容器。百度百科介紹
使用數據庫連接池可以:節約資源、提高訪問效率。
2. 數據源標準接口 —— javax.sql.DataSource
DataSource 是一個連接物理數據源的工廠,用於連接到此 DataSource 對象表示的物理數據源 。
除了用 DriverManager 對象獲取數據庫連接外,DataSource 對象是獲得數據庫連接的首選方法。
2.1 DataSource 的三種實現類型
實現類型 | 描述 |
---|---|
基本實現 | 創建一個標準的 Connection 對象。 |
連接池實現 | 創建一個 Connection 對象,該對象將自動參與連接池。 |
分佈式事務實現 | 創建一個 Connection 可用於分佈式事務的對象 |
2.2 部分相關的方法及描述
方法名 | 描述 |
---|---|
Connection getConnection() | 嘗試與數據源建立連接,返回連接對象。 |
Connection getConnection(String username, String password) | 嘗試與數據源建立連接,返回連接對象。 |
void close() | 歸還該 Connection 對象的數據庫 和 JDBC資源。 |
PrintWriter getLogWriter() | 檢索此 DataSource 對象的日誌編寫器。 |
2.3 C3P0 數據庫連接池
C3P0是一個開源的JDBC連接池,目前使用它的開源項目有Hibernate、Spring等。
2.3.1 使用步驟
-
導入jar包
- C3P0 jar包下載地址
- mysql-connector-java-8.0.17.jar : 注意與自己裝的數據庫版本對應。
- c3p0-0.9.5.2.jar
- mchange-commons-java-0.2.11.jar
-
定義配置文件
- 命名固定:c3p0.properties 或 c3p0-config.xml
- 放置路徑:src 路徑下
- 配置內容可以查看百度百科,後文會簡單介紹幾個。
-
創建核心對象
- ComboPooledDataSource
-
獲取連接對象
- 方法:getConnection
-
獲取連接對象後就可以進行其他JDBC相關的操作了,這裏不再演示。
2.3.2 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默認配置 -->
<default-config>
<!--連接參數,數據庫相關參數配置-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<!--連接池參數-->
<!--初始化申請的連接數量-->
<property name="initialPoolSize">10</property>
<!--最大的連接池數量-->
<property name="maxPoolSize">10</property>
<!--超時時間,單位爲毫秒-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 命名配置 -->
<named-config name="otherc3p0">
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">3000</property>
</named-config>
</c3p0-config>
注意數據庫參數配置:
- mysql 5.0 的驅動路徑爲:com.mysql.jdbc.Driver
- MySQL 8.0 的驅動路徑爲:com.mysql.cj.jdbc.Driver
- MySQL 8.0 之後必須加 : ?serverTimezone=UTC
- 如:jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC
- 否則會報錯時區錯誤。
2.3.3 Java代碼基本演示:獲取連接對象並打印到控制檯
package com.base.datasource.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0Demo1 {
public static void main(String[] args) throws SQLException {
//1.1 獲取DataSource,使用默認配置
// DataSource ds = new ComboPooledDataSource();
//1.2 獲取連接對象
// Connection conn = ds.getConnection();
//3. 打印
// System.out.println(conn);
// 2.1 獲取DataSource,使用指定名稱的配置
DataSource ds = new ComboPooledDataSource("otherc3p0");
for (int i=1;i<=10;i++){
// 2.2 獲取連接對象
Connection conn = ds.getConnection();
// 2.2 打印
System.out.println(i +" : "+ conn);
if (i == 5){
conn.close();
}
}
}
}
運行結果:
1 : com.mchange.v2.c3p0.impl.NewProxyConnection@6a5fc7f7 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@3b6eb2ec]
2 : com.mchange.v2.c3p0.impl.NewProxyConnection@6e8dacdf [wrapping: com.mysql.cj.jdbc.ConnectionImpl@7a79be86]
3 : com.mchange.v2.c3p0.impl.NewProxyConnection@b684286 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@880ec60]
4 : com.mchange.v2.c3p0.impl.NewProxyConnection@7f63425a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@36d64342]
5 : com.mchange.v2.c3p0.impl.NewProxyConnection@511baa65 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@340f438e]
6 : com.mchange.v2.c3p0.impl.NewProxyConnection@19dfb72a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@17c68925]
7 : com.mchange.v2.c3p0.impl.NewProxyConnection@3d24753a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@340f438e]
8 : com.mchange.v2.c3p0.impl.NewProxyConnection@7a0ac6e3 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@71be98f5]
9 : com.mchange.v2.c3p0.impl.NewProxyConnection@17f6480 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@2d6e8792]
Exception in thread "main" java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
注意:
- 配置文件裏面配置的初始化創建的連接池對象是5個,最大連接池對象是8個。
- 代碼展示中一共創建了10個連接對象,但是隻成功創建了9個連接對象,還剩一個出現超時異常(3秒左右)
- 能夠創建9個連接對象的原因是,我們歸還了第五個連接池對象,這個連接池對象被第七個連接對象獲取了,通過後面的哈希值可以判斷出這兩個連接池對象是同一個。
- 最後一個連接對象沒有創建成功的原因是,連接對象已經達到我們設定的最大連接數量 8個,如果沒有歸還的話,其他連接對象就不能被創建出來。
2.4 Druid 數據庫連接池
Apache Druid 是一個分佈式內存實時分析系統,用於解決如何在大規模數據集下進行快速的、交互式的查詢和分析。
2.4.1 使用步驟
-
導入jar包
- maven倉庫下載地址
- mysql-connector-java-8.0.17.jar
- druid-1.1.9.jar
-
配置文件
- 命名不固定。
- 是 properties 形式的。
- 可以放在任意路徑下。
-
加載配置文件
- 類:Properties
- 方法:
- getClassLoader()
- getResourceAsStream()
- load()
-
獲取數據庫連接池對象
- 通過工廠類獲取:DruidDataSourceFactory
-
獲取連接
- 獲取方法:getConnection()
2.4.2 配置文件
因爲命名沒有限制,這裏取名爲:druid.properties,內容如下:
# 數據庫連接參數信息
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC
username=root
password=root
# 初始化連接數量
initialSize=5
# 最大連接數
maxActive=10
# 最大等待時間
maxWait=3000
2.4.3 Java代碼基本演示:獲取並打印連接對象
package com.base.datasource.druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
* Druid連接池基本演示
*/
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1. 加載配置文件,類加載器
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2. 獲取連接池對象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//3. 獲取連接對象
Connection conn = ds.getConnection();
//4. 打印連接對象
System.out.println(conn);
}
}
運行結果:
com.mysql.cj.jdbc.ConnectionImpl@62e136d3
2.4.4 Druid 工具類編寫
- 編寫工具類 JDBCUtils
package com.base.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtils {
//1. 定義成員變量 DataSource
private static DataSource ds;
static {
try {
//1. 加載配置文件
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2. 獲取 DataSource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取連接
* @return Connection 對象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 釋放資源
* @param stmt Statement對象
* @param conn Connection對象
*/
public static void close(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 釋放資源方法重載
* @param rs ResultSet對象
* @param stmt Statement 對象
* @param conn Connection 對象
*/
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 獲取連接池對象
* @return ds 連接池對象
*/
public static DataSource getDataSource() {
return ds;
}
}
- 使用工具類創建連接,並執行簡單數據庫操作。
package com.base.datasource.druid;
import com.base.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 使用JDBC工具類
* 完成添加操作,給account添加一條記錄。
*/
public class DruidDemo2 {
public static void main(String[] args) throws Exception {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1. 獲取連接
conn = JDBCUtils.getConnection();
//2. 定義 SQL
String sql = "insert into account values(null,?,?)";
//3. 獲取 pstmt 對象
pstmt = conn.prepareStatement(sql);
//4. 給佔位符(?)賦值
pstmt.setString(1, "張三");
pstmt.setDouble(2, 2000);
//5. 執行 sql
int count = pstmt.executeUpdate();
System.out.println(count);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 釋放資源
JDBCUtils.close(pstmt, conn);
}
}
}
運行結果:
十月 31, 2019 4:24:03 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1
注意:沒有數據庫和對應的表需要提前創建一個,下面提供SQL代碼。
-- 創建數據庫
CREATE DATABASE IF NOT EXISTS demo_test CHARACTER SET utf8 ;
USE demo_test;
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) UNIQUE NOT NULL,
money VARCHAR(32) NOT NULL
);
時間:2019年10月31日15:59:13