DataSourceUitls類別位於org.springframework.jdbc.datasource套件下,提供了很多的靜態方法去從一個javax.sql.DataSource下取得JDBC Connection,並且提供了對Spring 事務管理的支持。
在JdbcTemplate類別的內部,DataSourceUtils被多次使用。其實,我們還可以在程式碼中直接使用DataSourceUitls來操作Jdbc。
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { try { return doGetConnection(dataSource); } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex); } catch (IllegalStateException ex) { throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage()); } }
可以看出,透過傳入一個指定的DataSource,可以取得一個Connection,取得過程由doGetConnection方法實作。如果拋出SQLException和IllegalStateException,則將其包裝成CannotGetJdbcConnectionException,事實上也只能拋出SQLException和IllegalStateException這兩種例外。透過檢視CannotGetJdbcConnectionException的原始碼,我們可以發現CannotGetJdbcConnectionException實際上是DataAccessException的子類,因此可以說,getConnection會將拋出的異常統一封裝成Spring的DataAccessException。
public static Connection doGetConnection(DataSource dataSource) throws SQLException { Assert.notNull(dataSource, "No DataSource specified"); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) { conHolder.requested(); if (!conHolder.hasConnection()) { logger.debug("Fetching resumed JDBC Connection from DataSource"); conHolder.setConnection(fetchConnection(dataSource)); } return conHolder.getConnection(); } // Else we either got no holder or an empty thread-bound holder here. logger.debug("Fetching JDBC Connection from DataSource"); Connection con = fetchConnection(dataSource); if (TransactionSynchronizationManager.isSynchronizationActive()) { logger.debug("Registering transaction synchronization for JDBC Connection"); // Use same Connection for further JDBC actions within the transaction. // Thread-bound object will get removed by synchronization at transaction completion. ConnectionHolder holderToUse = conHolder; if (holderToUse == null) { holderToUse = new ConnectionHolder(con); } else { holderToUse.setConnection(con); } holderToUse.requested(); TransactionSynchronizationManager.registerSynchronization( new ConnectionSynchronization(holderToUse, dataSource)); holderToUse.setSynchronizedWithTransaction(true); if (holderToUse != conHolder) { TransactionSynchronizationManager.bindResource(dataSource, holderToUse); } } return con; }
doGetConnection方法是用來實際操作取得Connection的核心方法。從原始程式碼可以得出,如果不存在與目前執行緒綁定的Connection,則新建一個全新的Connection,如果當前執行緒的事務同步處於活動狀態,那麼為剛剛建立的Connection新增Spring事務管理的支援;如果當前執行緒存在一個對應的Connection,那麼則有目前的事務管理分配。
fetchConnection是private方法,不對外公開,實際上是做了一個簡單的功能:從目前的DastaSource新建一個Connection,如果新建失敗,那麼拋出IllegalStateException ,提示不能取得一個新的Connection。
public static void releaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) { try { doReleaseConnection(con, dataSource); } catch (SQLException ex) { logger.debug("Could not close JDBC Connection", ex); } catch (Throwable ex) { logger.debug("Unexpected exception on closing JDBC Connection", ex); } }
releaseConnection方法的具體實作由doReleaseConnection處理。如果拋出異常,只是在日誌中做debug處理,不會對外拋出。此方法的兩個參數都存在NULL的情況,
如果con為NULL,則忽略本次呼叫;而另一個參數則被允許為NULL。
public static void doReleaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) throws SQLException { if (con == null) { return; } if (dataSource != null) { ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); if (conHolder != null && connectionEquals(conHolder, con)) { // It's the transactional Connection: Don't close it. conHolder.released(); return; } } logger.debug("Returning JDBC Connection to DataSource"); doCloseConnection(con, dataSource); }
doReleaseConnection方法是真正釋放了Connection的方法,與releaseConnection方法相比,則完成了傳入的兩個參數的校驗和拋出更底層的異常。在dataSource不為NULL的情況下,釋放此ConnectionHolder保留的目前連接,使得該目前的Connection可以得到重複使用,對提供Jdbc操作的效能很有幫助。如果dataSource為null的情況下則選擇直接關閉連線。
public static void doCloseConnection(Connection con, @Nullable DataSource dataSource) throws SQLException { if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) { con.close(); } }
在doReleaseConnection方法中,我們已經得知datasource為NULL的時候會執行doCloseConnection方法。事實上,只有dataSource沒有實作org.springframework.jdbc.datasource.SmartDataSource介面的時候或是dataSource實作了org.springframework.jdbc.datasource.SmartDataSource介面且允許關閉的時候,在真正關閉了Connection。
org.springframework.jdbc.datasource.SmartDataSource介面是 javax.sql.DataSource介面的一個擴展,用一種未包裝的形式傳回Jdbc的連接。實作該介面的類別可以查詢Connection在完成操作之後是否應該關閉。在Srping和DataSourceUitls和JdbcTemplate中會自動執行這樣的檢查。
以上是DataSourceUitls的介紹及方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!