數據庫(DataBase)-數據庫連接池代碼舉例

數據庫連接池

原數據庫連接機制:

數據庫連接——執行語句——執行完畢——釋放資源

在“連接——釋放”的過程中,是十分得浪費系統資源的。

因此,有了“池化技術”——預先準備好一些資源,等連接的時候,直接連上預先準備的。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章