DataUtils對Connection的獲取、釋放和關閉的操作學習


DataSourceUitls介紹

DataSourceUitls類位於org.springframework.jdbc.datasource包下,提供了很多的靜態方法去從一個javax.sql.DataSource下獲取JDBC Connection,並且提供了對Spring 事務管理的支持。

在JdbcTemplate類的內部,DataSourceUtils被多次使用。其實,我們還可以在代碼中直接使用DataSourceUitls來操作Jdbc。

DataSourceUitls獲取Connection

getConnection方法

內部實現

    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。

doGetConnection方法

內部實現

    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方法

fetchConnection是一個private方法,不對外公開,實際上是做了一個簡單的功能:從當前的DastaSource新建一個Connection,如果新建失敗,那么拋出IllegalStateException,提示不能獲取一個新的Connection。

DataSourceUitls釋放Connection

releaseConnection方法

內部實現

	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。

doReleaseConnection方法

內部實現

	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的情況下則選擇直接關閉連接。

DataSourceUitls關閉Connection

doCloseConnection方法

內部實現

	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是一個強大的工具輔助類,不僅僅是提供了Connection的獲取、釋放和關閉,其實還提供了為Connection提供Spring事務的支持。a


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM