11.3. 控制数据库连接

11.3.1. DataSourceUtils

DataSourceUtils作为一个帮助类提供易用且强大的数据库访问能力, 我们可以使用该类提供的静态方法从JNDI获取数据库连接以及在必要的时候关闭之。 它提供支持线程绑定的数据库连接(比如使用DataSourceTransactionManager的时候,将把数据库连接绑定到当前的线程上)。

11.3.2. SmartDataSource接口

SmartDataSourceDataSource 接口的一个扩展,用来提供数据库连接。使用该接口的类在指定的操作之后可以检查是否需要关闭连接。该接口在某些情况下非常有用,比如有些情况需要重用数据库连接。

11.3.3. AbstractDataSource

AbstractDataSource是一个实现了DataSource 接口的abstract基类。它实现了DataSource接口的 一些无关痛痒的方法,如果你需要实现自己的DataSource,那么可以继承该类。

11.3.4. SingleConnectionDataSource

SingleConnectionDataSourceSmartDataSource接口 的一个实现,其内部包装了一个单连接。该连接在使用之后将不会关闭,很显然它不能在多线程的环境下使用。

当客户端代码调用close方法的时候,如果它总是假设数据库连接来自连接池(就像使用持久化工具时一样), 你应该将suppressClose设置为true。这样,通过该类获取的将是代理连接(禁止关闭)而不是原有的物理连接。 需要注意的是,我们不能把使用该类获取的数据库连接造型(cast)为Oracle Connection之类的本地数据库连接。

SingleConnectionDataSource主要在测试的时候使用。它使得测试代码很容易脱离应用服务器而在一个简单的JNDI环境下运行。 与DriverManagerDataSource不同的是,它始终只会使用同一个数据库连接,从而避免每次建立物理连接的开销。

11.3.5. DriverManagerDataSource

DriverManagerDataSource类实现了 SmartDataSource接口。可以使用bean properties来设置JDBC Driver属性,该类每次返回的都是一个新的连接。

该类主要在测试以及脱离J2EE容器的独立环境中使用。它既可以用来在application context中作为一个DataSource bean,也可以在简单的JNDI环境下使用。 由于Connection.close()仅仅只是简单的关闭数据库连接,因此任何能够获取DataSource的持久化代码都能很好的工作。不过使用JavaBean风格的连接池 (比如commons-dbcp)也并非难事。即使是在测试环境下,使用连接池也是一种比使用DriverManagerDataSource更好的做法。

11.3.6. TransactionAwareDataSourceProxy

TransactionAwareDataSourceProxy作为目标DataSource的一个代理, 在对目标DataSource包装的同时,还增加了Spring的事务管理能力, 在这一点上,这个类的功能非常像J2EE服务器所提供的事务化的JNDI DataSource

注意

该类几乎很少被用到,除非现有代码在被调用的时候需要一个标准的 JDBC DataSource接口实现作为参数。 这种情况下,这个类可以使现有代码参与Spring的事务管理。通常最好的做法是使用更高层的抽象 来对数据源进行管理,比如JdbcTemplateDataSourceUtils等等。

如果需要更详细的资料,请参考 TransactionAwareDataSourceProxy JavaDocs。

11.3.7. DataSourceTransactionManager

DataSourceTransactionManager类是 PlatformTransactionManager接口的一个实现,用于处理单JDBC数据源。 它将从指定DataSource取得的JDBC连接绑定到当前线程,因此它也支持了每个数据源对应到一个线程。

我们推荐在应用代码中使用DataSourceUtils.getConnection(DataSource)来获取 JDBC连接,而不是使用J2EE标准的DataSource.getConnection。因为前者将抛出 unchecked的org.springframework.dao异常,而不是checked的 SQLException异常。Spring Framework中所有的类(比如 JdbcTemplate)都采用这种做法。如果不需要和这个 DataSourceTransactionManager类一起使用,DataSourceUtils 提供的功能跟一般的数据库连接策略没有什么两样,因此它可以在任何场景下使用。

DataSourceTransactionManager类支持定制隔离级别,以及对SQL语句查询超时的设定。 为了支持后者,应用代码必须使用JdbcTemplate或者在每次创建SQL语句时调用DataSourceUtils.applyTransactionTimeout(..)方法。

在使用单个数据源的情形下,你可以用DataSourceTransactionManager来替代JtaTransactionManager, 因为DataSourceTransactionManager不需要容器支持JTA。如果你使用DataSourceUtils.getConnection(DataSource)来获取 JDBC连接,二者之间的切换只需要更改一些配置。最后需要注意的一点就是JtaTransactionManager不支持隔离级别的定制!

11.3.8. NativeJdbcExtractor

有时我们需要执行特殊的,由特定厂商提供的与标准JDBC的API不同的JDBC方法。此时,当我们在某个应用服务器上运行包装了这些厂商各自实现的Connection, StatementResultSet对象的DataSource 时,可能会遇到一些问题。如果你要访问这些对象,你可以配置一个包含NativeJdbcExtractorJdbcTemplate或者OracleLobHandler

NativeJdbcExtractor根据执行环境的不同,会有不同的风格的实现:

  • SimpleNativeJdbcExtractor

  • C3P0NativeJdbcExtractor

  • CommonsDbcpNativeJdbcExtractor

  • JBossNativeJdbcExtractor

  • WebLogicNativeJdbcExtractor

  • WebSphereNativeJdbcExtractor

  • XAPoolNativeJdbcExtractor

通常来说SimpleNativeJdbcExtractor类对于绝大多数环境,已经足以屏蔽 Connection 对象。可以参见Java Docs获取详细信息。