數據庫連接池
原數據庫連接機制:
數據庫連接——執行語句——執行完畢——釋放資源
在“連接——釋放”的過程中,是十分得浪費系統資源的。
因此,有了“池化技術”——預先準備好一些資源,等連接的時候,直接連上預先準備的。
1.舉例:
1.原本從IDEA調用數據庫的東西,都需要有:
con = JdbcUtils.getConnection();
來建立連接,之後再
JdbcUtils.release(con,pres,res);
釋放資源。
現在直接準備好了許多個con,讓你用來建立連接,完成再歸還。無需在自己建立。
2.設想銀行的存取款:
銀行不是爲了你一個人開的,如果每個客戶去銀行,銀行都要開門一次,完成業務後,銀行就關門,下次再來客戶,再次開門。這是十分麻煩的。
因此,現在有一個機制:
銀行準備好一些員工,開門後等待客戶上門。員工等待着爲客戶服務,客戶來了之後,直接開始辦理業務。
這裏員工的數目,可以類比連接池的專業名詞:
常用連接數:27(通常情況下的同時辦理業務的人數)
最小連接數:Eg:7(最少有7個員工在等待爲客戶服務)
最大連接數:Eg:37(業務承載上限)
排隊等待:超過Eg:37之後的業務,需要等待前面的完成後再進行。
等待超時:Eg:100ms超過一定時間後,系統返回一個消息,讓程序取消等待,告訴他們不用再等了。
2.編寫連接池
通過一個接口:DataSource,來實現。
3.開源數據的實現
DBCP
(1)添加Jar包:commons-dbcp2-2.7.0.jar;commons-pool2-2.8.0.jar;
http://commons.apache.org/proper/commons-pool/download_pool.cgi
本文數據庫:
CREATE DATABASE JdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE JdbcStudy;
CREATE TABLE `users`(
`id` INT PRIMARY KEY,
`NAME` VARCHAR(40),
`PASSWORD` VARCHAR(40),
`email` VARCHAR(60),
`birthday` DATE
);
INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES
(1,'ALita','123456','[email protected]','2022-12-04'),
(2,'Edwin','456798','[email protected]','2000-12-04'),
(3,'Jarvis','789123','[email protected]','2000-12-04');
select * from user;
配置文件:
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcStudy?useUnicode = true&characterEncoding = utf8&useSSL = true
username = root
password = 1234
#DBCP配置文件
#連接設置,這裏的名字driverClassName,是DBCP數據源中定義好的
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&uesSSL=true
username=root
password=1234
#<!-- 初始化連接 -->
initialSize=10
#最大連接數量
maxActive=50
#<!-- 最大空閒連接 -->
maxIdle=20
#<!-- 最小空閒連接 -->
minIdle=5
#<!-- 超時等待時間以毫秒爲單位 6000毫秒/1000等於60秒 -->
maxWait=60000
#JDBC驅動建立連接時附帶的連接屬性屬性的格式必須爲這樣:【屬性名=property;】
#注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裏不需要包含他們。
connectionProperties=useUnicode=true;characterEncoding=utf8
#指定由連接池所創建的連接的自動提交(auto-commit)狀態。
defaultAutoCommit=true
#driver default 指定由連接池所創建的連接的只讀(read-only)狀態。
#如果沒有設置該值,則“setReadOnly”方法將不被調用。(某些驅動並不支持只讀模式,如:Informix)
defaultReadOnly=true
#driver default 指定由連接池所創建的連接的事務級別(TransactionIsolation)。
#可用值爲下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED
靜態方法:
package com.Edwin.lession05.utils;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author Edwin D
* @date 2020.5.23 上午 9:22
*/
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);
// 創建數據源,工廠模式:
// BasicDataSourceFactory->工廠
// createDataSource->創建對象
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
// 獲取連接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 釋放資源
public static void release(Connection con, Statement sta, ResultSet res) {
if (res != null) {
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (sta != null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
插入數據:
package com.Edwin.lession05;
import com.Edwin.lession05.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Date;
/**
* @author Edwin D
* @date 2020.5.23 下午 5:02
*/
public class TestDBCP {
public static void main(String[] args) {
Connection con = null;
PreparedStatement pres = null;
try {
con = JdbcUtils_DBCP.getConnection();
// PreparedStatement開始於Statement的有區別:
// 使用“?”佔位符來代替參數,可以提高效率,
String sql = "insert into `users` (`id`,`name`,`password`,`email`,`birthday`) values(?,?,?,?,?)";
pres = con.prepareStatement(sql);
// 此處的sql語句,屬於預編譯狀態,寫,但是不執行。
// 手動複製
pres.setInt(1,5);
pres.setString(2,"Duan");
pres.setString(3,"654321");
pres.setString(4,"[email protected]");
// 注意:Date的類型有多種:
// sql.Date -> 數據庫,代碼java.sql.Date()轉化時間。
// util.Date -> Java,代碼new Date().getTime()用於獲得時間戳,
pres.setDate(5,new java.sql.Date(new Date().getTime()));
// 執行
int i = pres.executeUpdate();
if (i > 0) {
System.out.println("TestDBCP insert Successful!");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils_DBCP.release(con,pres,null);
}
}
}
輸出由於某些玄學的東西,導致無法輸出,並且一直在報錯,無奈……等灑家解決了再寫一篇。
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class com.Edwin.lession05.utils.JdbcUtils_DBCP
at com.Edwin.lession05.TestDBCP.main(TestDBCP.java:43)
參考文獻
《【狂神說Java】MySQL最新教程通俗易懂》
視頻連接:https://www.bilibili.com/video/BV1NJ411J79W
2020.05.24