简介

数据库连接池是一个容器,负责分配、管理数据库的连接(Connection)。通过连接池可以让应用程序重复使用一个现有的数据库连接,而不是再重新建立一个,从而节省了大量时间。连接池还会释放空闲时间超过指定最大时长的数据库连接,以避免因为没有释放数据库连接而引起的数据库连接遗漏。
连接池的好处主要有三:

  • 资源复用
  • 提升系统响应速度
  • 防止数据库连接泄露

连接池访问数据库的优势及原理

JDBC连接的劣势

使用JDBC连接数据库

  1. 都需要创建一个Connection对象——应用程序 使用数据库驱动 建立的和数据库的间的连接是TCP连接
  2. 用户还需要进行身份验证,身份验证通过后应用才能进行读写数据库操作。
  3. 连接使用完毕后需要再将其销毁。而这种创建、销毁、再创建、再销毁的重复过程会特别耗费计算机性能以及程序运行时长。

而数据库如果使用了数据库连接池,就能达到Connection对象的复用效果。

数据库连接池的原理

数据库连接池在一开始就创建好了一些【数据库连接对象】存储起来。用户需要连接数据库时,不需要自己创建连接,只需要从连接池中获取一个进行使用就行了,使用完毕后将连接对象归还给连接池,由此实现了资源重用(自认指connection的创建和销毁),并节省了数据库连接的频繁创建、销毁所花费的时间,从而提高系统响应的速度。
在这里插入图片描述

开源项目 alibaba/druid 地址

此处给出alibaba/druid的GitHub地址https://github.com/alibaba/druid

使用方法

准备jar包

注意,使用Druid数据库连接池来实现数据库访问时,不仅需要druid的jar包,还需要对应数据库的访问jar包(否则会报错“java.sql.SQLException: com.mysql.cj.jdbc.Driver”)

此处先给出1.2.18版本druid的maven坐标。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.18</version>
</dependency>

定义Druid的配置文件

数据库驱动的名称driverClassName与直接使用JDBC jar包访问数据库时使用的名称一致。

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&useServerPrepStmts=true
username=root
password=
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

代码示例

待补入此文,下方示例好像是错的 = =,因为使用的DataSourcejavax.sql.DataSource,详见下方示例二。

示例一

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSourceFactory;

public class MySqlDatabaseConnectorUsingDruid {

	String currentFolder;
	Properties properties;
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySqlDatabaseConnectorUsingDruid druid = new MySqlDatabaseConnectorUsingDruid();
		druid.getDataFromMysql("");
	}

	private void getDataFromMysql(String sqlString) {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		if (sqlString.isBlank()) {
			sqlString = "select * from hogwarts_user;";
		}
		try {
			properties.load(new FileInputStream(currentFolder+File.separator+"src"+File.separator+"main"+File.separator+"java"+File.separator+"druid.properties"));
			//工厂模式获取连接池对象,通过读取properties中预定义的Druid属性来设置连接池,DataSource本身就没有提供构造方法。
			DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
			//从连接池中获取数据库连接Connection,从而减少新建Connection对象(connection = DriverManager.getConnection(DB_URL, "root", "");打开数据库链接)的时间
			connection = dataSource.getConnection();
			if (connection!=null) {
				statement = connection.createStatement();
				resultSet = statement.executeQuery(sqlString);
			}
			
			while (resultSet.next()) {
				String id = resultSet.getString("id");
				String nameString = resultSet.getString("name");
				String ageString = resultSet.getString("age");
						
				System.out.print("id是"+id);
				System.out.print(",name是"+nameString);
				System.out.println(",age是"+ageString);
				System.out.println("---------------");
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
			//如果在上方开启事务的话,此处需回滚事务
			待补代码
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			//如果在上方开启事务的话,此处需回滚事务
			待补代码
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			//如果在上方开启事务的话,此处需回滚事务
			待补代码
		}finally {
			if (resultSet!=null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			//如果在上方开启事务的话,此处需关闭事务


			if (statement!=null) {
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (connection!=null) {
				try {
					//只是将数据库连接池中占用的connection释放掉,使connection在连接池中处于空闲状态。网上有博客做过实验,可以参考[此博客](https://blog.csdn.net/killbibi/article/details/121364941)
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		
	}
	
	public MySqlDatabaseConnectorUsingDruid() {
		// TODO Auto-generated constructor stub
		currentFolder = System.getProperty("user.dir");
		properties = new Properties();
	}
}

示例二

使用Druid的数据源com.alibaba.druid.pool.DruidDataSource,如下所示。代码待验证

import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import com.alibaba.druid.pool.DruidDataSource;

public class DatabaseAccessorUsingDatabaseConnectionPool {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	
	public String getFromDatabaseUsingDatabaseConnectionPool() {
		
		String currentFolder = System.getProperty("user.dir");
		DruidDataSource  dataSource = null;
		Connection connection = null;
		try {
			//加载配置文件
	        Properties properties = new Properties();
	        properties.load(new FileInputStream(currentFolder+File.pathSeparator+"testMavenModule"+File.pathSeparator+"/com/druid.properties"));
	        //获取连接池对象
	        dataSource = new DruidDataSource();
	        //设置连接源
	        dataSource.setUrl(properties.getProperty("url"));
	        dataSource.setUsername(properties.getProperty("username"));
	        dataSource.setPassword(properties.getProperty("password"));
	        dataSource.setInitialSize(5); // 初始连接池大小
	        dataSource.setMinIdle(5); // 最小空闲连接数
	        dataSource.setMaxActive(20); // 最大活动连接数
	        dataSource.setValidationQuery("select 1 from dual");  // 心跳的 Query
	        dataSource.setMaxWait(60000); // 最大等待时间
	        dataSource.setTestOnBorrow(true); // 验证连接是否有效
	        //获取数据库连接
	        connection = dataSource.getConnection();
	        System.out.println(connection);
	        //connection其他xxxx操作
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}finally {
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			if (dataSource!=null) {
				dataSource.close();
			}
		}
		
		
		return "";
	}

}
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐