UnpooledDataSource

从名称上即可知道,该种数据源不具有池化特性。该种数据源每次会返回一个新的数据库连接,而非复用旧的连接。由于UnpooledDataSource无需提供连接池功能,因此它的实现非常简单。核心的方法有三个,分别如下:

  1. initializeDriver - 初始化数据库驱动
  2. doGetConnection - 获取数据连接
  3. configureConnection - 配置数据库连接

初始化数据库驱动

使用 JDBC 访问数据库时的情景,在执行SQL之前,通常都是先获取数据库连接。一般步骤都是加载数据库驱动,然后通过 DriverManager 获取数据库连接。UnpooledDataSource 也是使用 JDBC 访问数据库的,因此它获取数据库连接的过程也大致如此,只不过会稍有不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// -☆- UnpooledDataSource
private synchronized void initializeDriver() throws SQLException {
// 检测缓存中是否包含了与 driver 对应的驱动实例
if (!registeredDrivers.containsKey(driver)) {
Class<?> driverType;
try {
// 加载驱动类型
if (driverClassLoader != null) {
// 使用 driverClassLoader 加载驱动
driverType = Class.forName(driver, true, driverClassLoader);
} else {
// 通过其他 ClassLoader 加载驱动
driverType = Resources.classForName(driver);
}
// 通过反射创建驱动实例
Driver driverInstance = (Driver) driverType.newInstance();
// 注册驱动,注意这里是将 Driver 代理类 DriverProxy 对象注册到
// 而非 Driver 对象本身。DriverProxy 中并没什么特别的逻辑,就不分析。
DriverManager.registerDriver(new DriverProxy(driverInstance));
// 缓存驱动类名和实例
registeredDrivers.put(driver, driverInstance);
} catch (Exception e) {
throw new SQLException("……");
}
}
}

如上,initializeDriver 方法主要包含三步操作,分别如下:

  1. 加载驱动
  2. 通过反射创建驱动实例
  3. 注册驱动实例

上面代码中出现了缓存相关的逻辑,这个是用于避免重复注册驱动。因为initializeDriver 方法并不是在 UnpooledDataSource初始化时被调用的,而是在获取数据库连接时被调用的。因此这里需要做个检测,避免每次获取数据库连接时都重新注册驱动。

获取数据库连接

通过 DriverManager 的接口方法获取数据库连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// -☆- UnpooledDataSource
public Connection getConnection() throws SQLException {
return doGetConnection(username, password);
}

private Connection doGetConnection(String username, String password)
throws SQLException {
Properties props = new Properties();
if (driverProperties != null) {
props.putAll(driverProperties);
}
if (username != null) {
// 存储 user 配置
props.setProperty("user", username);
}
if (password != null) {
// 存储 password 配置
props.setProperty("password", password);
}
// 调用重载方法
return doGetConnection(props);
}

private Connection doGetConnection(Properties properties)
throws SQLException {
// 初始化驱动
initializeDriver();
// 获取连接
Connection connection = DriverManager.getConnection(url, properties);
// 配置连接,包括自动ᨀ交以及事务等级
configureConnection(connection);

return connection;
}

private void configureConnection(Connection conn) throws SQLException {
if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
// 设置自动提交
conn.setAutoCommit(autoCommit);
}
if (defaultTransactionIsolationLevel != null) {
// 设置事务隔离级别
conn.setTransactionIsolation(defaultTransactionIsolationLevel);
}
}

上面方法将一些配置信息放入到 Properties 对象中,然后将数据库连接和Properties 对象传给 DriverManager 的 getConnection 方法即可获取到数据库连接