数据库连接池的概念
假如没有连接池,我们操作数据库的流程如下:
-
应用程序使用数据库驱动建立和数据库的 TCP 连接 ;
-
用户进行身份验证 ;
-
身份验证通过,应用进行读写数据库操作 ;
-
操作结束后,关闭 TCP 连接 。
创建数据库连接是一个比较昂贵的操作,若同时有几百人甚至几千人在线,频繁地进行连接操作将占用更多的系统资源,但数据库支持的连接数是有限的,创建大量的连接可能会导致数据库僵死。
当我们有了连接池,应用程序启动时就预先建立多个数据库连接对象,然后将连接对象保存到连接池中。当客户请求到来时,从池中取出一个连接对象为客户服务。当请求完成时,客户程序调用关闭方法,将连接对象放回池中。
数据库连接池是一种资源管理技术,用于管理和复用数据库连接,避免频繁创建和销毁连接。使用数据库连接池可以提高应用程序的性能和响应速度,节省资源消耗,并提高系统的稳定性。通过池化技术,数据库连接池可以预先创建并维护一定数量的数据库连接,当应用程序需要时可以直接从池中获取连接,使用完毕后归还到池中,从而减少连接建立和销毁的时间和资源消耗。
- Apache Commons DBCP:这是一个开源的Java数据库连接池,由Apache软件基金会提供。它提供了可配置的、高性能的数据库连接池管理功能。
- HikariCP:HikariCP是一个轻量级、高性能的数据库连接池,被广泛认为是目前Java平台上性能最好的连接池之一。
- C3P0:C3P0是另一个流行的Java数据库连接池实现,提供了连接池的标准功能,并支持高级配置选项。
- Tomcat JDBC Pool:Tomcat JDBC Pool是Apache Tomcat项目的一个子项目,提供了快速、可靠的JDBC连接池实现,与Tomcat服务器集成良好。
- Druid:Druid是阿里巴巴开源的高性能数据库连接池,提供了强大的监控和扩展功能,被广泛应用于企业级项目中。
连接池的优点
1、资源重用:
因为数据库连接可以重用,避免了频繁创建,释放连接引起的大量性能开销,同时也增加了系统运行环境的平稳性。
2、提高性能
当业务请求时,因为数据库连接在初始化时已经被创建,可以立即使用,而不需要等待连接的建立,减少了响应时间。
3、优化资源分配
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源。
4、连接管理
数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
// druid 数据源
DruidDataSource druidDataSource = new DruidDataSource();
// 数据源配置
druidDataSource.setUrl(JDBC_URL);
druidDataSource.setUsername(USERNAME);
druidDataSource.setPassword(PASSWORD);
// 初始化
druidDataSource.init();
// 获取表名
Connection con = druidDataSource.getConnection();
Statement statement = con.createStatement();
ResultSet resultSet = statement.executeQuery("show tables");
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
}
con.close();
Druid连接池的使用
Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。Druid是阿里巴巴开发的号称为监控而生的数据库连接池!
Druid的简单使用
1、 首先在配置文件中导入好Druid连接池的依赖,还有MySQL的依赖
![]()
1 <dependency> 2 <groupId>mysql</groupId> 3 <artifactId>mysql-connector-java</artifactId> 4 <version>8.0.33</version> 5 </dependency> 6 7 <dependency> 8 <groupId>com.alibaba</groupId> 9 <artifactId>druid</artifactId> 10 <version>1.2.20</version> 11 </dependency>
![]()
2、编写Druid的配置文件 druid.properties
1 driverClassName=com.mysql.cj.jdbc.Driver 2 username=root 3 password=root 4 url=jdbc:mysql://localhost:3306/databasename 5 initialSize=5 6 maxActive=10
3、编写测试类进行CRUD操作
1 public class DruidFactory {
2 @Test
3 public void testDruidFactory() throws Exception {
4 Properties properties = new Properties();
5 InputStream resourceAsStream = DruidFactory.class.getClassLoader().getResourceAsStream("druid.properties");
6 properties.load(resourceAsStream);
7
8 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
9
10 Connection connection = dataSource.getConnection();
11
12 String sql = "SELECT * FROM users;";
13
14 PreparedStatement preparedStatement = connection.prepareStatement(sql);
15
16 ResultSet resultSet = preparedStatement.executeQuery();
17
18 ResultSetMetaData metaData = resultSet.getMetaData();
19
20 int columnCount = metaData.getColumnCount();
21
22 List<Map> list = new ArrayList<>();
23
24 while (resultSet.next()){
25 Map map = new HashMap();
26 for (int i = 1; i <= columnCount; i++) {
27 map.put(metaData.getColumnLabel(i),resultSet.getObject(i));
28 }
29 list.add(map);
30 }
31
32 Iterator<Map> iterator = list.iterator();
33
34 while (iterator.hasNext()){
35 System.out.println(iterator.next());
36 }
37
38 resultSet.close();
39
40 preparedStatement.close();
41
42 connection.close();
43
44 }
45 }
以上就是最基本的Druid连接池的使用,但是在实际上,我们不会每次都进行加载配置文件再获取连接这种操作,所以我们可以封装一个工具类来帮助我们简化连接操作
DruidUtils的简单封装
1 public class DruidConnection {
2 private static DataSource dataSource = null;
3
4 static {
5 Properties properties = new Properties();
6 InputStream resourceAsStream = DruidConnection.class.getClassLoader().getResourceAsStream("druid.properties");
7 try {
8 properties.load(resourceAsStream);
9 dataSource = DruidDataSourceFactory.createDataSource(properties);
10 }catch (Exception e) {
11 throw new RuntimeException(e);
12 }
13
14 }
15
16 public static Connection getConnection() throws SQLException {
17 return dataSource.getConnection();
18 }
19
20 public static void closeConnect(Connection connection) throws SQLException {
21 connection.close();
22 }
23 }
用静态代码块来获取连接,调用静态方法可以直接获取到连接,这样就简化了每次都要进行加载配置文件等繁琐操作,直接调用静态方法即可获取连接。
Druid对于线程的封装
1 public class DruidThread {
2 private static DataSource dataSource = null;
3 private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
4
5 static {
6 Properties properties = new Properties();
7 InputStream resourceAsStream = DruidThread.class.getClassLoader().getResourceAsStream("druid.properties");
8 try {
9 properties.load(resourceAsStream);
10 dataSource = DruidDataSourceFactory.createDataSource(properties);
11 } catch (Exception e) {
12 throw new RuntimeException(e);
13 }
14
15 }
16
17 public static Connection getConnection() throws SQLException {
18 Connection connection = threadLocal.get();
19 if (connection == null){
20 dataSource.getConnection();
21 threadLocal.set(connection);
22 }
23 return connection;
24 }
25
26 public static void closeConnection() throws SQLException {
27 Connection connection = threadLocal.get();
28 if (connection != null) {
29 threadLocal.remove();
30 connection.setAutoCommit(true);
31 connection.close();
32 }
33 }
34 }
将connection存放在线程本地量中,同一线程下的各业务逻辑层不需要用参数进行Connection传递,而且可以直接在线程本地量中获取当前i线程的连接,如果没有,那么创建一个新的连接。
Druid对于Dao层的操作封装
1 public class BaseDao {
2 // DML
3 public static int executeUpdate(String sql,Object... params) throws SQLException {
4 Connection connection = DruidConnection.getConnection();
5 PreparedStatement preparedStatement = connection.prepareStatement(sql,);
6 for (int i = 1; i <= params.length; i++) {
7 preparedStatement.setObject(i,params[i-1]);
8 }
9 int i = preparedStatement.executeUpdate();
10
11 preparedStatement.close();
12 DruidConnection.closeConnect(connection);
13 return i;
14 }
15
16 // DQL
17 public static <T> List<T> executeQuery(Class<T> clazz,String sql,Object... params) throws SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {
18
19 Connection connection = DruidConnection.getConnection();
20
21 PreparedStatement preparedStatement = connection.prepareStatement(sql);
22
23 if (params != null && params.length != 0){
24 for (int i = 1; i <= params.length; i++) {
25 preparedStatement.setObject(i,params[i-1]);
26 }
27 }
28
29 ResultSet resultSet = preparedStatement.executeQuery();
30 ResultSetMetaData metaData = resultSet.getMetaData();
31
32 List<T> list = new ArrayList();
33
34 int columnCount = metaData.getColumnCount();
35
36 while (resultSet.next()){
37 T t = clazz.newInstance();
38 for (int i = 1; i <= columnCount; i++) {
39 String columnLabel = metaData.getColumnLabel(i);
40 Object object = resultSet.getObject(i);
41 Field declaredField = clazz.getDeclaredField(columnLabel);
42 declaredField.setAccessible(true);
43 declaredField.set(t,object);
44 }
45 list.add(t);
46
47 }
48 resultSet.close();
49
50 preparedStatement.close();
51
52 DruidConnection.closeConnect(connection);
53
54 return list;
55 }
56 }
在Dao层操作数据库进行CRUD操作的时候,每次都要获取连接、创建prepareStatement对象,还要对结果集进行处理,太过于繁琐,于是将CRUD分成两大类进行封装,分别是DML和DQL。
在DQL中,使用集合存取结果集对象,集合的泛型是结果集对象的实体类,通过反射创建该实体类对象,然后通过getDeclaredField获取私有方法,并通过setAccessile设置private属性可访问,最后复制完将对象存到集合中。
Spring Boot 方式(推荐)
依赖
<!--引入druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
连接池配置:
spring:
datasource:
#数据源基本配置
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_crud
type: com.alibaba.druid.pool.DruidDataSource
#数据源其他配置
druid:
#配置初始化大小、最小、最大线程数
initialSize: 5
minIdle: 5
#CPU核数+1,也可以大些但不要超过20,数据库加锁时连接过多性能下降
maxActive: 20
# 最大等待时间,内网:800,外网:1200(三次握手1s)
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
#配置一个连接在池中最大空间时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
testWhileIdle: true
# 设置从连接池获取连接时是否检查连接有效性,true检查,false不检查
testOnBorrow: true
# 设置从连接池归还连接时是否检查连接有效性,true检查,false不检查
testOnReturn: true
#可以支持PSCache(提升写入、查询效率)
poolPreparedStatements: true
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
Druid连接池的主要配置项
配置 Druid 监控
Druid 提供了 Web 监控页面,可以查看连接池的状态和 SQL 监控等信息。要启用监控,需要添加以下配置:
Druid 提供了 Web 监控页面,可以查看连接池的状态和 SQL 监控等信息。要启用监控,需要添加以下配置:
# 配置 Druid 监控
spring:
datasource:
druid:
stat-view-servlet:
enabled: true
url-pattern: /druid/*
web-stat-filter:
enabled: true
url-pattern: /*
# 监控用户名和密码,用于登录监控页面
username: admin
password: admin

被折叠的 条评论
为什么被折叠?



