線程池-連接池-JDBC實例-JDBC連接池技術


線程池和連接池
  
線程池的原理:    
      來看一下線程池究竟是怎么一回事?其實線程池的原理很簡單,類似於操作系統中的緩沖區的概念,它的流程如下:先啟動若干數量的線程,並讓這些線程都處於睡眠狀態,當客戶端有一個新請求時,就會喚醒線程池中的某一個睡眠線程,讓它來處理客戶端的這個請求,當處理完這個請求后,線程又處於睡眠狀態。

 為什么要使用線程池:

  高峰期客戶端請求並發量大,如果為每個客戶端請求創建一個新線程的話,那耗費的CPU時間和內存將是驚人的,如果采用一個擁有多個線程的線程池,那將會節約大量的的系統資源,使得更多的CPU時間和內存用來處理實際的商業應用,而不是頻繁的線程創建與銷毀。

    數據庫連接池:
   一個數據庫連接對象均對應一個物理數據庫連接,每次操作都打開一個物理連接,使用完都關閉連接,這樣造成系統的 性能低下。

 數據庫連接解決方案:

  數據庫連接池(Connection Pool)。系統初始運行時,主動建立足夠的連接,組成一個池.每次應用應用程序請求數據庫連接時,無需重新打開連接,而是從池中取出已有的連接,使用完后,不再關閉,而是歸還。

  數據庫連接池的解決方案是在應用程序啟動時建立足夠的數據庫連接,並將這些連接組成一個連接池(簡單說:在一個“池”里放了好多半成品的數據庫聯接對象),由應用程序動態地對池中的連接進行申請、使用和釋放。對於多於連接池中連接數的並發請求,應該在請求隊列中排隊等待。並且應用程序可以根據池中連接的使用率,動態增加或減少池中的連接數。
  連接池技術盡可能多地重用了消耗內存地資源,大大節省了內存,提高了服務器地服務效率,能夠支持更多的客戶服務。通過使用連接池,將大大提高程序運行效率,同時,我們可以通過其自身的管理機制來監視數據庫連接的數量、使用情況等。
    1) 最小連接數是連接池一直保持的數據庫連接,所以如果應用程序對數據庫連接的使用量不大,將會有大量的數據庫連接資源被浪費;
    2) 最大連接數是連接池能申請的最大連接數,如果數據庫連接請求超過此數,后面的數據庫連接請求將被加入到等待隊列中,這會影響之后的數據庫操作。

 為什么要使用連接池技術?

  這個可以從數據庫連接缺陷和連接池優勢來回答。

  數據庫連接缺陷: 一個數據庫連接對象均對應一個物理數據庫連接,每次操作都打開一個物理連接,使用完都關閉連接,這樣造成系統的 性能低下。

  連接池技術:系統初始運行時,主動建立足夠的連接,組成一個池.每次應用應用程序請求數據庫連接時,無需重新打開連接,而是從池中取出已有的連接,使用完后,不再關閉,而是歸還。

 連接池的組成部分:連接池的建立、連接池中連接的使用管理、連接池的關閉。

  1.連接池的建立
    在系統初始化時,根據相應的配置創建連接並放置在連接池中,以便需要使用時能從連接池中獲取,這樣就可以避免連接隨意的建立、關閉造成的開銷。
  2.連接池中連接的使用管理
    連接池管理策略是連接池機制的核心。當連接池建立后,如何對連接池中的連接進行管理,解決好連接池內連接的分配和釋放,對系統的性能有很大的影響。連接的合理分配、釋放可提高連接的復用,降低了系統建立新連接的開銷,同時也加速了用戶的訪問速度。
        采用的方法是一個很有名的設計模式:Reference Counting(引用記數)。該模式在復用資源方面應用的非常廣泛,把該方法運用到對於連接的分配釋放上,為每一個數據庫連接,保留一個引用記數,用來記錄該連接的使用者的個數。
    (1)當客戶請求數據庫連接時,首先查看連接池中是否有空閑連接(指當前沒有分配出去的連接)。如果存在空閑連接,則把連接分配給客戶並作相應處理(即標記該連接為正在使用,引用計數加1)。如果沒有空閑連接,則查看當前所開的連接數是不是已經達到maxConn(最大連接數),如果沒達到就重新創建一個連接給請求的客戶;如果達到就按設定的maxWaitTime(最大等待時間)進行等待,如果等待maxWaitTime后仍沒有空閑連接,就拋出無空閑連接的異常給用戶。
    (2)當客戶釋放數據庫連接時,先判斷該連接的引用次數是否超過了規定值,如果超過就刪除該連接,並判斷當前連接池內總的連接數是否小於minConn(最小連接數),若小於就將連接池充滿;如果沒超過就將該連接標記為開放狀態,可供再次復用。可以看出正是這套策略保證了數據庫連接的有效復用,避免頻繁地建立、釋放連接所帶來的系統資源開銷。
  3.連接池的關閉
    當應用程序退出時,應關閉連接池,此時應把在連接池建立時向數據庫申請的連接對象統一歸還給數據庫(即關閉所有數據庫連接),這與連接池的建立正好是一個相反過程。
    我們采用DBCP(DataBase connection pool),數據庫連接池。DBCP(是 apache 上的一個 java 連接池項目,也是 tomcat 使用的連接池組件。單獨使用dbcp需要3個包:commons-dbcp.jar,commons-pool.jar,commons-collections.jar由於建立數據庫連接是一個非常耗時耗資源的行為,所以通過連接池預先同數據庫建立一些連接,放在內存中,應用程序需要建立數據庫連接時直接到連接池中申請一個就行,用完后再放回去。

 連接池的實現:

    1.使用Idea創建一個Maven項目,如下是Maven的項目結構:

    2.resources文件夾下面的db.properties文件

1 jdbc.driver=com.mysql.cj.jdbc.Driver
2 jdbc.url=jdbc:mysql://localhost:3306/crm01?useUnicode=true&characterEncoding=utf8
3 jdbc.user=root
4 jdbc.password=123456
5 initsize=1
6 maxactive=1
7 maxwait=5000
8 maxidle=1
9 minidle=1
#dbcp的基本配置的介紹
#1.initialSize :連接池啟動時創建的初始化連接數量(默認值為0)
#2.maxActive :連接池中可同時連接的最大的連接數(默認值為8,調整為20,高峰單機器在20並發左右,自己根據應用場景定)
#3.maxIdle:連接池中最大的空閑的連接數,超過的空閑連接將被釋放,如果設置為負數表示不限制
#(默認為8個,maxIdle不能設置太小,因為假如在高負載的情況下,連接的打開時間比關閉的時間快,會引起連接池中idle的個數 上升超過maxIdle,而造成頻繁的連接銷毀和創建,類似於jvm參數中的Xmx設置)
#4.minIdle:連接池中最小的空閑的連接數,低於這個數量會被創建新的連接(
#默認為0,調整為5,該參數越接近maxIdle,性能越好,因為連接的創建和銷毀,都是需要消耗資源的;但是不能太大,因為在機器很空閑的時候,也會創建低於minidle個數的連接,類似於jvm參數中的Xmn設置)
#5.maxWait  :最大等待時間,當沒有可用連接時,連接池等待連接釋放的最大時間,超過該時間限制會拋出異常,
#如果設置-1表示無限等待(默認為無限,調整為60000ms,避免因線程池不夠用,而導致請求被無限制掛起)

  

  3.DBUtil.java

package com.yuanziren;
import org.apache.commons.dbcp.BasicDataSource;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 使用連接池技術管理數據庫連接
 */
public class DBUtil {
    
    //數據庫連接池
    private static BasicDataSource dbcp;
    
    //為不同線程管理連接
    private static ThreadLocal<Connection> tl;
    
    //通過配置文件來獲取數據庫參數
    static{
        try{
            Properties prop = new Properties();
            InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
            prop.load(is);
            is.close();
            //一、初始化連接池
            dbcp = new BasicDataSource();
            //設置驅動 (Class.forName())
            dbcp.setDriverClassName(prop.getProperty("jdbc.driver"));
            //設置url
            dbcp.setUrl(prop.getProperty("jdbc.url"));
            //設置數據庫用戶名
            dbcp.setUsername(prop.getProperty("jdbc.user"));
            //設置數據庫密碼
            dbcp.setPassword(prop.getProperty("jdbc.password"));
            //初始連接數量
            dbcp.setInitialSize(Integer.parseInt(prop.getProperty("initsize")));
            //連接池允許的最大連接數
            dbcp.setMaxActive(Integer.parseInt(prop.getProperty("maxactive")));
            //設置最大等待時間
            dbcp.setMaxWait(Integer.parseInt(prop.getProperty("maxwait")));
            //設置最小空閑數
            dbcp.setMinIdle(Integer.parseInt(prop.getProperty("minidle")));
            //設置最大空閑數
            dbcp.setMaxIdle(Integer.parseInt(prop.getProperty("maxidle")));
            //初始化線程本地
            tl = new ThreadLocal<Connection>();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 獲取數據庫連接
     * @return
     * @throws SQLException 
     */
    public static Connection getConnection() throws SQLException {
        /*
         * 通過連接池獲取一個空閑連接
         */
        Connection conn = dbcp.getConnection();
        tl.set(conn);
        return conn;
    }

    /**
     * 關閉數據庫連接
     */
    public static void closeConnection(){
        try{
            Connection conn = tl.get();
            if(conn != null){
                /*
                 * 通過連接池獲取的Connection
                 * 的close()方法實際上並沒有將
                 * 連接關閉,而是將該鏈接歸還。
                 */
                conn.close();
                tl.remove();
            }    
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 測試是否連接成功
     * @param args
     * @throws SQLException
     */
    public static void main(String[] args) throws SQLException {
        System.out.println(getConnection());
    }
}

    4.pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5   <modelVersion>4.0.0</modelVersion>
 6 
 7   <groupId>com.yuanziren</groupId>
 8   <artifactId>dbcp</artifactId>
 9   <version>1.0-SNAPSHOT</version>
10 
11   <name>dbcp</name>
12   <!-- FIXME change it to the project's website -->
13   <url>http://www.example.com</url>
14 
15   <properties>
16     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
17     <maven.compiler.source>1.8</maven.compiler.source>
18     <maven.compiler.target>1.8</maven.compiler.target>
19   </properties>
20 
21   <dependencies>
22     <dependency>
23       <groupId>junit</groupId>
24       <artifactId>junit</artifactId>
25       <version>4.12</version>
26       <scope>test</scope>
27     </dependency>
28     <dependency>
29       <groupId>commons-dbcp</groupId>
30       <artifactId>commons-dbcp</artifactId>
31       <version>1.4</version>
32     </dependency>
33     <dependency>
34       <groupId>org.apache.commons</groupId>
35       <artifactId>commons-pool2</artifactId>
36       <version>2.6.2</version>
37     </dependency>
38     <dependency>
39       <groupId>org.apache.commons</groupId>
40       <artifactId>commons-collections4</artifactId>
41       <version>4.3</version>
42     </dependency>
43     <dependency>
44       <groupId>mysql</groupId>
45       <artifactId>mysql-connector-java</artifactId>
46       <version>8.0.16</version>
47     </dependency>
48   </dependencies>
49 
50   <build>
51   </build>
52 </project>

    4.運行結果

    5.代碼實現中遇到的Bug

      參考博客:

        JDBC連接MYSQL數據庫失敗:Loading class `com.mysql.jdbc.Driver'. This is deprecated.

        https://blog.csdn.net/weixin_42323802/article/details/82589743

        空指針問題:java.lang.NullPointerException at java.util.Properties$LineReader.readLine(Properties.java:434)問題

          https://blog.csdn.net/qq_41562136/article/details/83722473

        時區問題:

          https://blog.csdn.net/yongjiutongmi53151/article/details/86504546

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM