线程池和链接池
线程池的原理:
来看一下线程池到底是怎么一回事?其实线程池的原理很简单,相似于操做系统中的缓冲区的概念,它的流程以下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态。java
为何要使用线程池:mysql
高峰期客户端请求并发量大,若是为每一个客户端请求建立一个新线程的话,那耗费的CPU时间和内存将是惊人的,若是采用一个拥有多个线程的线程池,那将会节约大量的的系统资源,使得更多的CPU时间和内存用来处理实际的商业应用,而不是频繁的线程建立与销毁。
数据库链接池:
一个数据库链接对象均对应一个物理数据库链接,每次操做都打开一个物理链接,使用完都关闭链接,这样形成系统的 性能低下。web
数据库链接解决方案:sql
数据库链接池(Connection Pool)。系统初始运行时,主动创建足够的链接,组成一个池.每次应用应用程序请求数据库链接时,无需从新打开链接,而是从池中取出已有的链接,使用完后,再也不关闭,而是归还。数据库
数据库链接池的解决方案是在应用程序启动时创建足够的数据库链接,并将这些链接组成一个链接池(简单说:在一个“池”里放了好多半成品的数据库联接对象),由应用程序动态地对池中的链接进行申请、使用和释放。对于多于链接池中链接数的并发请求,应该在请求队列中排队等待。而且应用程序能够根据池中链接的使用率,动态增长或减小池中的链接数。
链接池技术尽量多地重用了消耗内存地资源,大大节省了内存,提升了服务器地服务效率,可以支持更多的客户服务。经过使用链接池,将大大提升程序运行效率,同时,咱们能够经过其自身的管理机制来监视数据库链接的数量、使用状况等。
1) 最小链接数是链接池一直保持的数据库链接,因此若是应用程序对数据库链接的使用量不大,将会有大量的数据库链接资源被浪费;
2) 最大链接数是链接池能申请的最大链接数,若是数据库链接请求超过此数,后面的数据库链接请求将被加入到等待队列中,这会影响以后的数据库操做。apache
为何要使用链接池技术?设计模式
这个能够从数据库链接缺陷和链接池优点来回答。tomcat
数据库链接缺陷: 一个数据库链接对象均对应一个物理数据库链接,每次操做都打开一个物理链接,使用完都关闭链接,这样形成系统的 性能低下。服务器
链接池技术:系统初始运行时,主动创建足够的链接,组成一个池.每次应用应用程序请求数据库链接时,无需从新打开链接,而是从池中取出已有的链接,使用完后,再也不关闭,而是归还。并发
链接池的组成部分:链接池的创建、链接池中链接的使用管理、链接池的关闭。
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(); //1、初始化链接池 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