29. //创建Statement
30. stmt = conToUse.createStatement(); 31. applyStatementSettings(stmt); 32. Statement stmtToUse = stmt;
33. if (this.nativeJdbcExtractor != null) {
34. stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt); 35. }
36. //这里调用回调函数
37. T result = action.doInStatement(stmtToUse); 38. handleWarnings(stmt); 39. return result; 40. }
41. catch (SQLException ex) {
42. // Release Connection early, to avoid potential connection pool deadlock
43. // in the case when the exception translator hasn't been initialized yet.
44. //如果捕捉到数据库异常,把数据库Connection释放,同时抛出一个经过Spring转换过的Spring数据库异常
45. //Spring做了一项有意义的工作,就是把这些数据库异常统一到自己的异常体系里了
46. JdbcUtils.closeStatement(stmt); 47. stmt = null;
48. DataSourceUtils.releaseConnection(con, getDataSource());
49. con = null;
50. throw getExceptionTranslator().translate(\back\
51. } 52. finally {
53. JdbcUtils.closeStatement(stmt); 54. //释放数据库connection
55. DataSourceUtils.releaseConnection(con, getDataSource()); 56. } 57.}
在使用数据库的时候,有一个很重要的地方就是对数据库连接的管理,在这里,是由DataSourceUtils来完成的。Spring通过这个辅 助类来对数据的Connection进行管理。比如通过它来完成打开和关闭Connection等操作。DataSourceUtils对这些数据库 Connection管理的实现, 如以下代码所示。 Java代码
1. //这是取得数据库连接的调用,实现是通过调用doGetConnection完成的,这里执行了异常的转换操作
2. public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { 3. try {
4. return doGetConnection(dataSource); 5. }
6. catch (SQLException ex) {
7. throw new CannotGetJdbcConnectionException(\et JDBC Connection\8. } 9. }
10.public static Connection doGetConnection(DataSource dataSource) throws SQLException {
11. Assert.notNull(dataSource, \12. //把对数据库的Connection放到事务管理中进行管理,这里使用TransactionSynchronizationManager中定义的ThreadLocal变量来和线程绑定数据库连接
13. //如果在TransactionSynchronizationManager中已经有与当前线程绑定数据库连接,那就直接取出来使用
14. ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
15. if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) { 16. conHolder.requested();
17. if (!conHolder.hasConnection()) {
18. logger.debug(\ DataSource\
19. conHolder.setConnection(dataSource.getConnection());
20. }
21. return conHolder.getConnection(); 22. }
23. // Else we either got no holder or an empty thread-bound holder here.
24. // 这里得到需要的数据库Connection,在Bean配置文件中定义好的,
25. // 同时最后把新打开的数据库Connection通过
TransactionSynchronizationManager和当前线程绑定起来。 26. logger.debug(\27. Connection con = dataSource.getConnection(); 28.
29. if (TransactionSynchronizationManager.isSynchronizationActive()) {
30. logger.debug(\or JDBC Connection\
31. // Use same Connection for further JDBC actions within the transaction.
32. // Thread-bound object will get removed by synchronization at transaction completion.
33. ConnectionHolder holderToUse = conHolder; 34. if (holderToUse == null) {
35. holderToUse = new ConnectionHolder(con); 36. } 37. else {
38. holderToUse.setConnection(con); 39. }
40. holderToUse.requested();
41. TransactionSynchronizationManager.registerSynchronization(
42. new ConnectionSynchronization(holderToUse, dataSource));
43. holderToUse.setSynchronizedWithTransaction(true); 44. if (holderToUse != conHolder) {
45. TransactionSynchronizationManager.bindResource(dataSource, holderToUse); 46. } 47. }
48. return con; 49.}
关于数据库操作类RDBMS
从JdbcTemplate中,我们看到,他提供了许多简单查询和更新的功能。但是,如果需要更高层次的抽象,以及更面向对象的方法来访问数据 库,Spring为我们提供了org.springframework.jdbc.object包,里面包含了SqlQuery、 SqlMappingQuery、SqlUpdate和StoredProcedure等类,这些类都是Spring JDBC应用程序可以使用的。但要注意,在使用这些类时需要为它们配置好
JdbcTemplate作为其基本的操作实现,因为在它们的功能实现中,对数据 库操作的那部分实现基本上还是依赖于JdbcTemplate来完成的。
比如,对MappingSqlQuery使用的过程,是非常简洁的;在设计好数据的映射代码之后,查询得到的记录已经按照前面的设计转换为对象 List了,一条查询记录对应于一个数据对象,可以把数据库的数据记录直接映射成Java对象在程序中使用,同时又可避免使用第三方ORM工具的配置,对 于简单的数据映射场合是非常方便的;在mapRow方法的实现中提供的数据转换规则,和我们使用Hibernate时,Hibernate的hbm文件起 到的作用是非常类似的。这个MappingSqlQuery需要的对设置进行compile,这些compile是这样完成的,如以下代码所示: Java代码
1. protected final void compileInternal() { 2. //这里是对参数的compile过程,所有的参数都在getDeclaredParameters里面,生成了一个PreparedStatementCreatorFactory
3. this.preparedStatementFactory = new PreparedStatementCreatorFactory(getSql(), getDeclaredParameters());
4. this.preparedStatementFactory.setResultSetType(getResultSetType());