连接池的实现:Druid实现。
目录
1.Druid下载
2.将Druid的jar包添加进工程
3.Druid连接池:初体验案例
(1)创建druid-config.properties文件
(2)编写DruidSample类
(3)总结,分析(重要!!!)
4.Druid连接池的几个点
(1)【initialSize=10】和【maxActive=20】属性设置
(2)【initialSize=10】默认连接数不够的话,会启动最大连接数【maxActive=20】属性
(3)如果程序中数据库连接数的需求超过最大连接数,那些没有分配到的程序会等待
(4)【initialSize】和【maxActive】建议设置相同值(重要!!!)
5.在实际中使用时的疑问?????(后续明确了,再回头改)
1.Druid下载
总之,在Druid的Github主页上,各种点点总能找到对应的下载链接。
https://repo1.maven.org/maven2/com/alibaba/druid/为druid的下载链接;
2.将Druid的jar包添加进工程
然后,将Druid的jar包加入到工程依赖中;
这儿没有勾选,就直接点击OK了,勾选与否的区别是什么???待解答
说明:
这里的Dependencies是指这里勾选引入的依赖包可以在当前Module下使用。查看下lib目录下对应的jar包前是否有个小箭头,如果有,也是表示将该jar包添加到项目中,所以这里不勾选也是可以使用的;
emm,个人感觉,以后是是勾选上吧。。。。
3.Druid连接池:初体验案例
(1)创建druid-config.properties文件
这个配置文件的名字可以改~~~
首先,在src下创建一个全新的properties属性文件:druid-config.properties文件。用来保存JDBC运行时必要的信息。
然后,需要在druid-config.properties属性文件中,配置JDBC的信息;
(以前的JDBC的代码都写在了java代码中,Druid的配置为什么不也写在java代码中,而是要写在属性文件中?)Druid为了让程序程序拥有更好的可维护性;试想一下,如果将用户名、密码、连接字符串都存放到java源代码中,那么每一次更改后,都需要对源代码进行重新编译、重新部署才可以生效;;;而如果放在druid-config.properties属性文件这个配置文件中,其本身就是一个纯粹的文本文件,所以当需要修改数据库信息的时候,直接修这个文件,然后重启应用就能生效了。
在druid-config.properties属性文件配置:可配置项;
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/imooc?useSSL=false&useUincode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username=root
password=12345
JDBC的信息都放在了配置文件中,那么如何利用Druid对这些配置的信息进行加载和读取?
(2)编写DruidSample类
DruidSample类:(1)加载属性文件;(2)获取DataSource数据源对象;(3)创建数据库连接。
package com.imooc.jdbc.sample;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.imooc.jdbc.common.DbUtils;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
/**
* Druid连接池配置与使用
*/
public class DruidSample {
public static void main(String[] args) {
//1.加载属性文件
Properties properties = new Properties();
//以前接触过,DruidSample.class.getResource(“某个文件”)获取当前类路径下对应文件的路径;
String propertiesFile = DruidSample.class.getResource("/druid-config.properties").getPath();
System.out.println("***"+propertiesFile+"***");
try {
// 容纳错考虑:提取的配置文件路径:base64编码转成utf-8编码;(以前遇到过)
propertiesFile = new URLDecoder().decode(propertiesFile,"UTF-8");
properties.load(new FileInputStream(propertiesFile));
} catch (UnsupportedEncodingException | FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//2.获取DataSource数据源对象
// DataSource数据源对象:java.sql提供的一个接口;利用DataSource指代我们要操作的数据库是什么;
// DataSource也提供了获取数据库连接的方法;;;所谓数据源就是数据库在JDBC中的别称;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//通过DruidDataSourceFactory工厂类,创建数据源;
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//3.创建数据库连接
conn = dataSource.getConnection();
pstmt = conn.prepareStatement("select * from employee limit 0,10");
rs = pstmt.executeQuery();
while (rs.next()) {
Integer eno = rs.getInt(1);
String ename = rs.getString("ename");
Float salary = rs.getFloat("salary");
String dname = rs.getString("dname");
System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
/**
* 不使用连接池:conn.close()关闭连接;
* 使用连接池:conn.close()将连接回收至连接池;
*/
DbUtils.closeConnection(rs,pstmt,conn);
}
}
}
DruidSample类几点说明:
(1)【String propertiesFile = DruidSample.class.getResource("/druid-config.properties").getPath();】DruidSample.class.getResource(“某个文件”)获取当前类路径下对应文件的路径;同时,也对获取到的路径字符串转化了编码方式;(前台系统二这篇博客中的XmlDataSource类部分有类似内容)
(2)作为Java来说,在src下,所存放的不只有程序的源代码,还有相关的配置文件,这个配置文件会随着运行一起被发布到最终的out目录下,产生在工程的运行环境中;
即编译后,所有Java类编译后的class文件都在out目录下;同样,在src中的其他配置文件也会出现在out目录中。
(3)导入的包说明:
运行结果:
(3)总结,分析(重要!!!)
发现,在使用Druid之后,好像有点无感,Druid创建的连接在哪儿?怎么没有看到?
其实可以这样理解:
(1)在设置了配置文件(druid-config.properties)之后,启动程序之后,数据库连接池中就已经有数据库连接,这些连接池中的数据库连接等待被取用;;;
(2)然后,在程序中,通过Properties类读取那个配置文件,然后通过Druid提供的工厂类DruidDataSourceFactory去记载读取的配置文件,就能得到DataSource数据源对象;
(3)DataSource数据源对象可以认为是访问数据库连接池的一个对象,通过DataSource数据源可以获取数据库连接池中的连接;
在需要使用数据库的地方,就创建一个DataSource对象,然后利用DataSource对象去线程池中取一个数据库连接就好了啊。
(4)一切就绪之后,当程序中需要数据库连接的时候,直接使用【conn = dataSource.getConnection();】从数据库连接池中去取一个连接就可以了;;;;;;而不用再使用【Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUincode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true", "root", "12345");】去现创建数据库连接了;
(5)即,如果没有数据库连接池的话,每当程序中需要数据库连接的时候,都是需要使用而不用再使用【Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUincode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true", "root", "12345");】去现创建数据库连接的,这个速度就会比较慢;;;;肯定没有(4)中那样,直接去连接池中去取现成的、已经创建好的连接快啊。
附加一个说明:
4.Druid连接池的几个点
(1)【initialSize=10】和【maxActive=20】属性设置
在druid-config.properties中设置两个属性:
【initialSize=10】:连接池刚启动准备好,会默认的创建10个数据库连接;
【maxActive=20】:如果在实际项目运行中,10个连接不够用,连接池会额外的再创建新的数据库连接,但总数不得超过20;
如果在程序运行中,连接池创建的连接已经达到了上限,连接还不够用的话,那些没有分到数据库连接的程序就会一直进入等待的状态,等待其他正在使用连接池中连接的程序调用close()方法,然后连接池就会将数据库连接进行回收,然后那些苦苦等待的程序就会有数据库连接可用,然后去执行了。
通过Navicat工具的【服务器监控】界面中可以看到目前所有已创建的数据库连接:
……………………………………………………
(2)【initialSize=10】默认连接数不够的话,会启动最大连接数【maxActive=20】属性
可以发现,初始的数量不够用了,连接池会自动的帮我们扩展新的连接,直到达到允许的上限;
……………………………………………………
(3)如果程序中数据库连接数的需求超过最大连接数,那些没有分配到的程序会等待
如:
这也是在实际中使用数据库连接池时需要注意的点。在实际中,一旦程序达到生产的服务器上,运行一段时间后,程序就无缘无故的被卡死,这很有可能是数据库连接池的最大数量设置的不够了,从而让程序一直处于等待的状态。
那么连接池最大数量设置多少合适?需要根据实际项目的情况来决定,比如通常1个用户使用1个数据库连接,那么就要测算在最忙碌的时候,同时会有多少个用户来使用我们的系统。最大的连接数量一定要超过最大的用户数,才能保证程序不会因为这个问题而阻塞。
……………………………………………………
(4)【initialSize】和【maxActive】建议设置相同值(重要!!!)
一个比较不错的技巧,也是很多资深开发者的做法:将初始的数量(【initialSize】)和最大的数量(【maxActive】)把持一致;比如【initialSiz=20】,【maxActive=20】,都设置成20;
这是因为:在日常工作中,应用程序最好在一开始就把所有的连接和资源都分配好,用户进来了以后直接获取现成的资源,避免出现重新创建资源的情况;这样对于整体的程序管理和性能都是有帮助的。
5.在实际中使用时的疑问?????(后续明确了,再回头改)
*************************************************************************************************
首先有两个前提:
前提1:Druid连接池连接池的初始化需要使用Druid的配置文件;
前提2:在工程启动的时候,需要初始化连接池;
三个疑问:
疑问1:加载属性文件得到Properties对象的初始化代码放在哪儿?(这些初始化代码肯定是在工程启动的时候就要执行啊,这样才能提前准备好Druid连接池);是不是把这些工作放在那些工程启动时会默认先执行的代码中?
疑问2:Properties对象是做成一个全局可访问的变量吗?
疑问3:数据源对象DateSource对象,是在哪儿创建的?是和Properties对象的初始化代码放在一起,做成全局变量;还是在需要使用数据库连接的地方,再现创建?换句话说,在整个项目中,是只有一个DateSource对象,还是有多个DataSource对象?
Answer:
1、不可以更改名字
2、new Properties()这个操作就是在得到properties对象
3、Properties对象是做成一个全局可访问的变量吗?
这里创建Properties对象是为了加载配置文件,没有必要定义成全局可以访问的变量
3、1)通过DruidDataSourceFactory工程类的createDataSource()方法在底层创建DataSource数据源
2)用到时再创建即可
3)是可以有多个DataSource对象的
*************************************************************************************************
目前我的理解,在实际使用中。使用了Druid以后,工程启动之后,那些数据库连接就已经存在了。然后在需要使用数据库连接的时候,通过上面的步骤,直接去获取连接就好了。