当前位置 : 主页 > 编程语言 > java >

【老王读Spring Transaction-6】spring-tx与DataSource连接池整合的原理

来源:互联网 收集:自由互联 发布时间:2022-08-15
@TOC 前言 javax.sql.DataSource 是 java 提供的一个获取 DB 连接的标准接口。 它的实现类可以通过简单的实现,生成标准的连接对象;也可以使用连接池方式实现,生成的池化的连接对象。 通

@TOC

前言

javax.sql.DataSource 是 java 提供的一个获取 DB 连接的标准接口。 它的实现类可以通过简单的实现,生成标准的连接对象;也可以使用连接池方式实现,生成的池化的连接对象。

通常在企业级的开发当中,我们都会使用池化的连接对象,比如使用 apache 的 DBCP 连接池、阿里的 druid 连接池、springboot 默认使用的 hikari 连接池等

那么,DataSource 是如何与 spring-tx 进行结合的呢?

spring-tx 的核心关注点是事务的管理。连接的获取和关闭是交给连接池去实现的。 其实, spring-tx 管理的是 事物连接。(后续会细说)

public interface DataSource extends CommonDataSource, Wrapper { /** * 尝试与此 DataSource 对象表示的数据源建立连接 */ Connection getConnection() throws SQLException; Connection getConnection(String username, String password) throws SQLException; }

Spring 版本

spring-tx 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

spring-tx 中获取事物连接是通过 DataSourceTransactionManager#doGetTransaction() 来获取的:

// org.springframework.jdbc.datasource.DataSourceTransactionManager protected Object doGetTransaction() { DataSourceTransactionObject txObject = new DataSourceTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed()); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource()); txObject.setConnectionHolder(conHolder, false); return txObject; } protected DataSource obtainDataSource() { DataSource dataSource = getDataSource(); Assert.state(dataSource != null, "No DataSource set"); return dataSource; }

获取连接最终会委托到 DataSourceUtils#doGetConnection() 来获取。

org.springframework.jdbc.datasource.DataSourceUtils: DataSourceUtils 是通过静态方法,从指定的 DataSource 获取 JDBC 连接的 helper 类。 它里面包含了对 spring 管理的事物连接的特殊支持。(通常是指被 DataSourceTransactionManager 管理的事务连接)。

事物连接: Spring-managed transactional Connections

DataSourceUtils 的源码注释中有一段话: Helper class that provides static methods for obtaining JDBC Connections from a DataSource. Includes special support for Spring-managed transactional Connections, e.g. managed by DataSourceTransactionManager or org.springframework.transaction.jta.JtaTransactionManager.

里面提到了 Spring-managed transactional Connections。这里要强调一下: JDBC Connection 与 Spring-managed transactional Connections 是有区别的。 通常所说的 JDBC Connection 是普通的 jdbc 连接。而 Spring-managed transactional Connections 是受 Spring 管理的事物连接(通常 @Transactional 标记的事物方法使用的就是 Spring 管理的事物连接)。 可以通过 DataSourceUtils#isConnectionTransactional(Connection con, DataSource dataSource) 方法去判断一个 jdbc 连接是否是一个 Spring 管理的事物连接。 而非事物连接通常也是从 DataSource 中获取的,只是这些非事物连接不是被事物管理器 DataSourceTransactionManager 来管理的。

DataSourceTransactionManager 的类图如下: TransactionManager.png

spring-tx 与 DataSource 的整合

TransactionManager 自动配置的源码:DataSourceTransactionManagerAutoConfiguration.png

可以看到,TransactionManager 这个 bean 的创建依赖 DataSource 这个 bean。这样,Spring 管理的 DataSource 就与 spring-tx 整合在一起了。 连接的获取就是通过 Spring 管理的 DataSource 来获取的。

SpringBoot 默认使用的 DataSource 连接池是 Hikari

SpringBoot 通过 spring-boot-autoconfigure.jar 来自动配置 DataSource。具体是在 spring.factories 中有一行配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

自动加载配置时,就会加载 Hikari 的配置: HikariDataSource.png

事物连接的关闭/释放: 并不是真正的关闭

事物连接的关闭/释放 并不是真正的关闭,而只是将引用数减 1,当减到 0 的时候,就认为这个连接没有被使用到了。

// org.springframework.jdbc.datasource.ConnectionHolder#released() /** * Releases the current Connection held by this ConnectionHolder. * <p>This is necessary for ConnectionHandles that expect "Connection borrowing", * where each returned Connection is only temporarily leased and needs to be * returned once the data operation is done, to make the Connection available * for other operations within the same transaction. */ public void released() { super.released(); // 不是真正的释放,而只是将引用数减 1 if (!isOpen() && this.currentConnection != null) { if (this.connectionHandle != null) { this.connectionHandle.releaseConnection(this.currentConnection); } this.currentConnection = null; } }

小结

spring-tx 获取连接最终会委托给 DataSourceUtils#doGetConnection() 来获取。 而 DataSourceUtils 在获取连接时,使用的 DataSource 是 spring 管理的一个 bean。 在 SpringBoot 中,默认使用的是 HikariDataSource。具体是在 DataSourceAutoConfiguration 中进行配置的。

上一篇:CERC2012 A - kingdoms 状态压缩dp
下一篇:没有了
网友评论