Spring自己提供了一個簡單的數據源實現類DriverManagerDataSource ,它位於org.springframework.jdbc.datasource包中。這個類實現了javax.sql.DataSource接口,但 它並無提供池化鏈接的機制,每次調用getConnection()獲取新鏈接時,只是簡單地建立一個新的鏈接。所以,這個數據源類比較適合在單元測試 或簡單的獨立應用中使用,由於它不須要額外的依賴類。分析這樣一段代碼:java
package com.jason.spring.datasource.jdbc; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import javax.sql.DataSource; import java.util.List; import java.util.Map; public class TestSpringJDBC { public static void main(String[] args) { final ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/spring-jdbc.xml"); final DataSource dataSource = (DataSource) applicationContext.getBean("jdbcDataSource"); TransactionTemplate transactionTemplate = (TransactionTemplate) applicationContext.getBean("transactionTemplate"); try { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); List<Map<String, Object>> map = jdbcTemplate.queryForList("select * from test.order for update "); System.out.println(map); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { try { JdbcTemplate jdbcTemplate = (JdbcTemplate)applicationContext.getBean("jdbcTemplate"); List<Map<String, Object>> map = jdbcTemplate.queryForList("select * from test.order for update "); System.out.println(map); } catch (Exception e) { status.setRollbackOnly(); } } }); //System.in.read(); } catch (Exception e) { e.printStackTrace(); } } }
對應的spring的配置文件:mysql
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <bean id="jdbcDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="jdbcDataSource"/> </bean> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="jdbcDataSource"/> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="dataSourceTransactionManager"/> <property name="isolationLevelName" value="ISOLATION_DEFAULT"/> </bean> </beans>
會執行到JdbcTemplate中的以下方法:spring
public <T> T execute(StatementCallback<T> action) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); Connection con = DataSourceUtils.getConnection(getDataSource()); Statement stmt = null; try { Connection conToUse = con; if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) { conToUse = this.nativeJdbcExtractor.getNativeConnection(con); } stmt = conToUse.createStatement(); applyStatementSettings(stmt); Statement stmtToUse = stmt; if (this.nativeJdbcExtractor != null) { stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt); } T result = action.doInStatement(stmtToUse); handleWarnings(stmt); return result; } catch (SQLException ex) { // Release Connection early, to avoid potential connection pool deadlock // in the case when the exception translator hasn't been initialized yet. JdbcUtils.closeStatement(stmt); stmt = null; DataSourceUtils.releaseConnection(con, getDataSource()); con = null; throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex); } finally { JdbcUtils.closeStatement(stmt); DataSourceUtils.releaseConnection(con, getDataSource()); } }
從該段代碼能夠看到,其Connection 是經過DataSourceUtils.getConnection(getDataSource())去拿到的,繼續跟進去: 會到org.springframework.jdbc.datasource.DataSourceUtils中的:sql
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(dataSource.getConnection()); } 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 = dataSource.getConnection(); 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; }
在資源釋放時,會有區別:無事務時,直接釋放數據源,有事務時,暫時不真正的釋放數據源app
public static void doReleaseConnection(Connection con, 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); }