|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
控制数据库连接
使用DataSource
Spring 通过 DataSource 获取数据库连接。DataSource 是 JDBC 规范的一部分,是一个通用的连接工厂。它允许容器或框架将连接池和事务管理等细节从应用程序代码中隐藏起来。作为开发人员,你无需了解如何连接数据库的具体细节,这是负责配置数据源的管理员的职责。在开发和测试代码时,你很可能同时承担这两个角色,但你并不一定需要知道生产环境中的数据源是如何配置的。
当你使用 Spring 的 JDBC 层时,可以从 JNDI 获取数据源,也可以使用第三方提供的连接池实现来配置自己的数据源。
传统的选择是 Apache Commons DBCP 和 C3P0,它们提供 bean 风格的 DataSource 类;
对于现代的 JDBC 连接池,建议使用具有构建器风格 API 的 HikariCP。
您应该仅在测试目的时使用DriverManagerDataSource 和 SimpleDriverDataSource 类(这些类包含在 Spring 发行版中)!
那些变体不提供连接池功能,并且当需要多次请求连接时性能较差。 |
以下部分使用了Spring的DriverManagerDataSource实现。
其他DataSource变体将在后面进行介绍。
要配置一个DriverManagerDataSource:
-
使用
DriverManagerDataSource获得连接,就像您通常获取JDBC连接一样。 -
指定完整的类名(fully qualifiedclassname)的JDBC驱动,以便
DriverManager可以加载驱动类。 -
提供一个根据JDBC驱动程序不同而变化的URL。请参见您所使用的驱动程序的文档以获取正确的值。
-
提供一个用户名和密码以连接到数据库。
以下示例展示了如何在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 类是一个便捷而强大的辅助类,提供了static方法用于从 JNDI 获取连接,并在必要时关闭连接。
它支持与 Connection 绑定到线程的 JDBC DataSourceTransactionManager,同时也支持 JtaTransactionManager 和 JpaTransactionManager。
注意,JdbcTemplate 暗示了 DataSourceUtils 连接访问,在每次JDBC操作的背后都隐式地参与了一个正在进行的事务。
实现SmartDataSource
SmartDataSource 接口应由能够提供关系型数据库连接的类来实现。它扩展了 DataSource 接口,使得使用它的类可以查询在执行某个操作后是否应关闭该连接。当你知道需要重用连接时,这种用法非常高效。
扩展AbstractDataSource
AbstractDataSource 是 Spring abstract 实现的DataSource基类。它实现了所有 DataSource 实现所共用的代码。
如果你要编写自己的 AbstractDataSource 实现,应当继承 DataSource 类。
使用SingleConnectionDataSource
SingleConnectionDataSource 类是 SmartDataSource 接口的一个实现,它封装了一个单一的 Connection,该连接在每次使用后不会被关闭。
此实现不具备多线程能力。
如果任何客户端代码在假定使用连接池的情况下调用 close 方法(例如使用持久化工具时),您应将 suppressClose 属性设置为 true。此设置会返回一个抑制关闭操作的代理对象,该代理包装了物理连接。请注意,此后您将无法再将其强制转换为原生的 Oracle Connection 或类似对象。
SingleConnectionDataSource 主要是一个测试类。它通常与一个简单的 JNDI 环境结合使用,便于在应用服务器之外轻松测试代码。
与 DriverManagerDataSource 不同,它始终重用同一个连接,避免了频繁创建物理连接。
使用DriverManagerDataSource
The 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 管理的事务中。通常更推荐使用更高层次的资源管理抽象(例如 JdbcTemplate 或 DataSourceUtils)来编写新的代码。 |
请参阅 TransactionAwareDataSourceProxy
javadoc 以获取更多详情。
使用DataSourceTransactionManager / JdbcTransactionManager
DataSourceTransactionManager 类是针对单个 JDBC PlatformTransactionManager 的 DataSource 实现。它将来自指定 Connection 的 JDBC DataSource 绑定到当前执行的线程,从而可能为每个 Connection 提供一个线程绑定的 DataSource。
应用程序代码需要通过 Connection 来获取 JDBC DataSourceUtils.getConnection(DataSource),而不是使用 Java EE 标准的 DataSource.getConnection。它会抛出非受检的 org.springframework.dao 异常,而不是受检的 SQLExceptions。所有框架类(例如 JdbcTemplate)都隐式地使用了这一策略。如果未与事务管理器一起使用,该查找策略的行为与 DataSource.getConnection 完全相同,因此在任何情况下都可以使用。
DataSourceTransactionManager 类支持保存点(PROPAGATION_NESTED)、自定义隔离级别,以及作为适当的 JDBC 语句查询超时应用的超时设置。为了支持后者,应用程序代码必须使用 JdbcTemplate,或者为每个创建的语句调用 DataSourceUtils.applyTransactionTimeout(..) 方法。
在单一资源的情况下,你可以使用 DataSourceTransactionManager 代替 JtaTransactionManager,因为前者不需要容器支持 JTA 事务协调器。只要遵循所需的连接查找模式,这两种事务管理器之间的切换仅涉及配置的更改。请注意,JTA 不支持保存点(savepoints)或自定义隔离级别,并且具有不同的超时机制,但在 JDBC 资源以及 JDBC 提交/回滚管理方面,其行为与前者类似。
从 5.3 版本开始,Spring 提供了一个扩展的 JdbcTransactionManager 变体,该变体在提交/回滚时增加了异常转换功能(与 JdbcTemplate 保持一致)。
DataSourceTransactionManager 仅会抛出 TransactionSystemException(类似于 JTA),
而 JdbcTransactionManager 会将数据库锁失败等情况转换为相应的 DataAccessException 子类。
请注意,应用程序代码需要为此类异常做好准备,而不能仅仅预期 TransactionSystemException。
在此类场景下,推荐使用 JdbcTransactionManager。 |
在异常行为方面,JdbcTransactionManager 大致等同于 JpaTransactionManager,也等同于 R2dbcTransactionManager,三者可互为直接的配套组件或替代品。另一方面,DataSourceTransactionManager 则等同于 JtaTransactionManager,可直接替代后者。