線程池和連接池 線程池的原理: 來看一下線程池究竟是怎麼一回事?其實線程池的原理很簡單,類似於操作系統中的緩衝區的概念,它的流程如下:先啟動若幹數量的線程,並讓這些線程都處於睡眠狀態,當客戶端有一個新請求時,就會喚醒線程池中的某一個睡眠線程,讓它來處理客戶端的這個請求,當處理完這個請求後,線程又處於 ...
線程池和連接池
線程池的原理:
來看一下線程池究竟是怎麼一回事?其實線程池的原理很簡單,類似於操作系統中的緩衝區的概念,它的流程如下:先啟動若幹數量的線程,並讓這些線程都處於睡眠狀態,當客戶端有一個新請求時,就會喚醒線程池中的某一個睡眠線程,讓它來處理客戶端的這個請求,當處理完這個請求後,線程又處於睡眠狀態。
為什麼要使用線程池:
高峰期客戶端請求併發量大,如果為每個客戶端請求創建一個新線程的話,那耗費的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