概述
当我们用第三方工具去连接数据库(Mysql,Oracle 等)的时候,一般都会让我们选择数据源,我们以 MySQL 为例,当选择 MySQL 的时候就会弹出如下图显示的界面:
其中,我们在选择了 Driver(驱动)和 Host、UserName、Password 等之后,就可以创建一个 Connection,然后连接到数据库里面了。
同样的道理,在 Java 里面我们也需要用到 DataSource 去连接数据库,而 Java 定义了一套 JDBC 的协议标准,其中有一个 javax.sql.DataSource 接口类,通过实现此类就可以进行数据库连接。
源码分析
DataSource 接口里面主要的代码如下:
public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password)
throws SQLException;
}
我们通过源码可以很清楚地看到,DataSource 的主要目的就是获得数据库连接,就像我们前面用工具连接数据库一样,只不过工具是通过界面实现的,而 DataSource 是通过代码实现的。
那么在程序里面如何实现呢?也有很多第三方的实现方式,常见的有C3P0、BBCP、Proxool、Druid、Hikari,而目前 Spring Boot 里面是采用 Hikari 作为默认数据源。Hikari 的优点是:开源,社区活跃,性能高,监控完整。
其中,当我采用默认数据源的时候,可以看到数据源的实现类有:h2 里面的 JdbcDataSource、MySQL 连接里面的 MysqlDataSource,以及今天要重点介绍的 HikariDataSource(默认数据源,也是 Spring 社区推荐的最佳数据源)。
查看HikariDataSource源码:
public class HikariDataSource extends HikariConfig implements DataSource, Closeable{
private volatile HikariPool pool;
public HikariDataSource(HikariConfig configuration)
{
configuration.validate();
configuration.copyStateTo(this);
LOGGER.info("{} - Starting...", configuration.getPoolName());
pool = fastPathPool = new HikariPool(this);
LOGGER.info("{} - Start completed.", configuration.getPoolName());
this.seal();
}
//这个是最主要的实现逻辑,即通过连接池获得连接的逻辑
public Connection getConnection() throws SQLException{
if (isClosed()) {
throw new SQLException("HikariDataSource " + this + " has been closed.");
}
if (fastPathPool != null) {
return fastPathPool.getConnection();
}
// See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null) {
synchronized (this) {
result = pool;
if (result == null) {
validate();
LOGGER.info("{} - Starting...", getPoolName());
try {
pool = result = new HikariPool(this);
this.seal();
}
catch (PoolInitializationException pie) {
if (pie.getCause() instanceof SQLException) {
throw (SQLException) pie.getCause();
}
else {
throw pie;
}
}
LOGGER.info("{} - Start completed.", getPoolName());
}
}
}
return result.getConnection();
}
......
}
HikariConfig 的配置里面描述了 Hikari 数据源主要的配置属性,我们打开来看一下:
通过上面的源码我们可以看到数据源的关键配置信息:用户名、密码、连接池的配置、jdbcUrl、驱动的名字,等等,这些字段你可以参考课程开始时我介绍的工具,细心观察的话都可以找到对应关系,也就是创建数据源需要的一些配置项。
我们通过 getConnection 方法里面的代码可以看到 HikariPool 的用法,也就是说,我们是通过连接池来获得连接的,这个连接用过之后没有断开,而是重新放回到连接池里面(这个地方你一定要谨记,它也说明了 connection 是可以共享的)。
而连接池的用途你应该也知道,创建连接是非常昂贵的,所以需要用到连接池技术、共享现有的连接,以增加代码的执行效率。
数据源与驱动与连接和连接池的关系
1、数据源的作用是给应用程序提供不同 DB 的连接 connection;
2、连接是通过连接池获取的,这主要是出于连接性能的考虑;
3、创建好连接之后,通过数据库的驱动来进行数据库操作;
4、而不同的 DB(MySQL / h2 / oracle),都有自己的驱动类和相应的驱动 Jar 包。
而我们常说的 MySQL 驱动,其实就是 com.mysql.cj.jdbc.Driver,而这个类主要存在于 mysql-connection-java:8.0* 的 jar 里面,也就是我们经常说的不同的数据库所代表的驱动 jar 包。
这里我们用的是 spring boot 2.3.3 版本引用的 mysql-connection-java 8.0 版本驱动 jar 包,不同的数据库引用的 jar 包是不一样的。例如,H2 数据源中,我们用的驱动类是 org.h2.Driver,其包含在 com.h2database:h2:1.4.*jar 包里面。
后续学习数据源的加载原理和过程,再进行补充~