控制数据库连接

使用 DataSource

Spring通过 DataSource 获取与数据库的连接。 DataSource 是JDBC规范的一部分,是一个通用的连接工厂。它允许容器或框架将连接池和事务管理问题隐藏在应用程序代码之外。作为开发人员,您不需要了解如何连接到数据库的详细信息。这是设置数据源的管理员的责任。在开发和测试代码时,您很可能会兼顾这两个角色,但不一定需要了解生产数据源的配置方式。

当您使用Spring的JDBC层时,可以从JNDI获取数据源,或者可以使用第三方提供的连接池实现来配置自己的数据源。传统的选择是使用Apache Commons DBCP和C3P0提供的基于bean风格的 DataSource 类;对于现代的JDBC连接池,请考虑使用HikariCP及其构建器风格的API。

仅应将 DriverManagerDataSourceSimpleDriverDataSource 类(包含在Spring分发中)用于测试目的!这些变体不提供连接池,并且在请求多个连接时性能较差。

以下部分使用了Spring的 DriverManagerDataSource 实现。稍后将介绍几种其他 DataSource 变体。

要配置 DriverManagerDataSource

  1. 像通常获取JDBC连接一样使用 DriverManagerDataSource 获取连接。

  2. 指定JDBC驱动程序的完全限定类名,以便 DriverManager 可以加载驱动程序类。

  3. 提供一个因JDBC驱动程序而异的URL。(请参阅您的驱动程序的文档以获取正确的值。)

  4. 提供用户名和密码以连接到数据库。

以下示例显示了如何在Java中配置 DriverManagerDataSource

  • Java

  • Kotlin

DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa");
dataSource.setPassword("");
val dataSource = DriverManagerDataSource().apply {
	setDriverClassName("org.hsqldb.jdbcDriver")
	url = "jdbc:hsqldb:hsql://localhost:"
	username = "sa"
	password = ""
}

以下示例显示了相应的XML配置:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="${jdbc.driverClassName}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

<context:property-placeholder location="jdbc.properties"/>

接下来的两个示例展示了DBCP和C3P0的基本连接和配置。要了解更多有助于控制连接池功能的选项,请参阅各自连接池实现的产品文档。

以下示例显示了DBCP的配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="${jdbc.driverClassName}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

<context:property-placeholder location="jdbc.properties"/>

以下示例显示了C3P0的配置:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
	<property name="driverClass" value="${jdbc.driverClassName}"/>
	<property name="jdbcUrl" value="${jdbc.url}"/>
	<property name="user" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

<context:property-placeholder location="jdbc.properties"/>

使用 DataSourceUtils

DataSourceUtils 类是一个方便且强大的辅助类,提供了从JNDI获取连接并在必要时关闭连接的 static 方法。它支持基于线程的JDBC Connection,可以与 DataSourceTransactionManager 一起使用,也可以与 JtaTransactionManagerJpaTransactionManager 一起使用。

请注意,JdbcTemplate 隐含使用 DataSourceUtils 进行连接访问,在每个JDBC操作后使用它,隐式参与进行中的事务。

实现 SmartDataSource

SmartDataSource 接口应该由能够提供与关系数据库的连接的类实现。它扩展了 DataSource 接口,让使用它的类查询在给定操作后连接是否应该关闭。当您知道需要重用连接时,此用法是有效的。

扩展 AbstractDataSource

AbstractDataSource 是Spring的 DataSource 实现的抽象基类。它实现了所有 DataSource 实现共有的代码。如果您编写自己的 DataSource 实现,应该扩展 AbstractDataSource 类。

使用 SingleConnectionDataSource

SingleConnectionDataSource 类是 SmartDataSource 接口的实现,它包装一个不会在每次使用后关闭的单个 Connection。这不支持多线程。

如果任何客户端代码在假定使用连接池时调用 close(例如在使用持久性工具时),应将 suppressClose 属性设置为 true。此设置返回一个包装物理连接的关闭抑制代理。请注意,您不能再将其转换为本机Oracle Connection 或类似对象。

SingleConnectionDataSource 主要是一个测试类。它通常使得在应用程序服务器之外轻松测试代码,与简单的JNDI环境结合使用。与 DriverManagerDataSource 相比,它始终重用相同的连接,避免过度创建物理连接。

使用 DriverManagerDataSource

DriverManagerDataSource 类是标准 DataSource 接口的实现,通过bean属性配置普通的JDBC驱动程序,并在每次返回新的 Connection

此实现对于Jakarta EE容器之外的测试和独立环境非常有用,可以作为Spring IoC容器中的 DataSource bean,或者与简单的JNDI环境结合使用。假设连接池的 Connection.close() 调用会关闭连接,因此任何了解 DataSource 的持久性代码都应该正常工作。但是,即使在测试环境中,使用JavaBean风格的连接池(如 commons-dbcp)也很容易,因此几乎总是更倾向于使用这样的连接池而不是 DriverManagerDataSource

使用 TransactionAwareDataSourceProxy

TransactionAwareDataSourceProxy是目标 DataSource 的代理。该代理包装了目标 DataSource,以增加对Spring管理事务的感知能力。在这方面,它类似于由Jakarta EE服务器提供的具有事务性的JNDI DataSource

除非必须调用并传递标准的JDBC DataSource接口实现,否则很少需要使用这个类。在这种情况下,您仍然可以使这段代码可用,并且同时使这段代码参与Spring管理的事务。通常最好通过使用更高级别的资源管理抽象,如 JdbcTemplateDataSourceUtils,编写自己的新代码。

查看 TransactionAwareDataSourceProxy javadoc 以获取更多详细信息。

使用 DataSourceTransactionManager / JdbcTransactionManager

DataSourceTransactionManager 类是用于单个JDBC DataSourcePlatformTransactionManager 实现。它将来自指定 DataSource 的JDBC Connection 绑定到当前执行的线程,可能允许每个 DataSource 有一个线程绑定的 Connection

应用程序代码需要通过 DataSourceUtils.getConnection(DataSource) 而不是Java EE的标准 DataSource.getConnection 来检索JDBC Connection。它会抛出未经检查的 org.springframework.dao 异常,而不是经过检查的 SQLExceptions。所有框架类(如 JdbcTemplate)都隐式地使用这种策略。如果不使用事务管理器,查找策略的行为与 DataSource.getConnection 完全相同,因此可以在任何情况下使用。

DataSourceTransactionManager 类支持保存点(PROPAGATION_NESTED)、自定义隔离级别和适用于适当的JDBC语句查询超时的超时。为了支持后者,应用程序代码必须使用 JdbcTemplate 或为每个创建的语句调用 DataSourceUtils.applyTransactionTimeout(..) 方法。

在单资源情况下,您可以使用 DataSourceTransactionManager 而不是 JtaTransactionManager,因为它不需要容器支持JTA事务协调器。在这些事务管理器之间切换只是一种配置问题,只要遵循所需的连接查找模式即可。请注意,JTA不支持保存点或自定义隔离级别,并且具有不同的超时机制,但在JDBC资源和JDBC提交/回滚管理方面以类似的行为公开。

对于JTA风格的实际资源连接的延迟检索,Spring为目标连接池提供了相应的 DataSource 代理类:请参阅 LazyConnectionDataSourceProxy。这对于可能为空的事务而没有实际语句执行(在这种情况下从不获取实际资源)非常有用,并且也适用于路由 DataSource 的前端,该前端需要考虑事务同步的只读标志和/或隔离级别(例如 IsolationLevelDataSourceRouter)。

LazyConnectionDataSourceProxy 还为只读连接池提供了特殊支持,以在只读事务期间使用,避免在从主连接池获取连接时在每个事务的开始和结束时切换JDBC Connection的只读标志的开销(这可能会根据JDBC驱动程序而昂贵)。

从5.3版本开始,Spring提供了一个扩展的 JdbcTransactionManager 变体,它在提交/回滚时添加了异常转换功能(与 JdbcTemplate 对齐)。在这种情况下,DataSourceTransactionManager 只会抛出 TransactionSystemException(类似于JTA),JdbcTransactionManager 将数据库锁定失败等转换为相应的 DataAccessException 子类。请注意,应用程序代码需要准备处理这些异常,而不仅仅期望 TransactionSystemException。在这种情况下,推荐使用 JdbcTransactionManager
JdbcTransactionManagerJpaTransactionManagerR2dbcTransactionManager 大致相当,可以作为彼此的直接伴侣/替代品。另一方面, DataSourceTransactionManager 相当于 JtaTransactionManager,可以直接替代。