《Spring技术内幕》学习笔记11——JdbcTemplate封装Jdbc

1.Spring中使用JdbcTemplate封装对Jdbc的支持,使用Spring JdbcTeamplate的例子如下:

(1).假设如下SQL表中有数据username=test1,passwd=test1,address=test1 :

 

CREATE TABLE `login` ( 
  `username` varchar(10) default NULL, 
  `passwd` varchar(10) default NULL, 
  `address` varchar(10) default NULL 
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

 

(2).Spring配置文件中添加关于数据源和JdbcTeamplate的配置如下:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" > 
<beans> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
   <property name="driverClassName"> 
     <value>com.mysql.jdbc.Driver</value> 
   </property> 
   <property name="url"> 
     <value>jdbc:mysql://localhost:3306/javaee</value> 
   </property> 
   <property name="username"> 
     <value>root</value> 
   </property> 
   <property name="password"> 
     <value>1234</value> 
   </property> 
</bean> 
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
   <property name="dataSource"> 
     <ref local="dataSource"/> 
   </property> 
</bean> 
<bean id="personDAO" class="SpringJDBCSupport.ReadData.PersonDAO"> 
  <property name="jdbcTemplate"> 
    <ref local="jdbcTemplate"/> 
  </property> 
</bean> 
</beans>


(3).Java持久化对象如下:

package SpringJDBCSupport.ReadData; 
import com.mysql.jdbc.Driver; 
public class Person { 
  private String name; 
  private String password; 
  private String address; 
  public Person(){ 
  } 
  public Person(String name,String password,String address){ 
      this.name=name; 
      this.password=password; 
      this.address=address; 
  } 
public String getAddress() { 
    return address; 
} 
public void setAddress(String address) { 
    this.address = address; 
} 
public String getName() { 
    return name; 
} 
public void setName(String name) { 
    this.name = name; 
} 
public String getPassword() { 
    return password; 
} 
public void setPassword(String password) { 
    this.password = password; 
} 
public String toString(){ 
    return this.getName()+"-"+this.getPassword()+"-"+this.getAddress(); 
} 
}

(4).使用JdbcTeamplateDAO如下:

package SpringJDBCSupport.ReadData; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Types; 
import java.util.List; 
import org.springframework.jdbc.core.BatchPreparedStatementSetter; 
import org.springframework.jdbc.core.JdbcTemplate; 
import org.springframework.jdbc.core.RowCallbackHandler; 
public class PersonDAO { 
  private JdbcTemplate jdbcTemplate; 
public JdbcTemplate getJdbcTemplate() { 
    return jdbcTemplate; 
} 
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { 
    this.jdbcTemplate = jdbcTemplate; 
} 
public int insertPersonUseUpdate(Person person){ 
    String sql="insert into login values(?,?,?)"; 
    Object[] params=new Object[]{ 
            person.getName(), 
            person.getPassword(), 
            person.getAddress() 
    }; 
    return this.getJdbcTemplate().update(sql,params); 
} 
public int insertPersonUseExecute(Person person){ 
    String sql="insert into login values(?,?,?)"; 
    Object[] params=new Object[]{ 
            person.getName(), 
            person.getPassword(), 
            person.getAddress() 
    }; 
    int[] types=new int[]{ 
            Types.VARCHAR, 
            Types.VARCHAR, 
            Types.VARCHAR 
    }; 
    return this.getJdbcTemplate().update(sql,params,types); 
} 
public int[] updatePersonUseBatchUpdate( final List persons){ 
    String sql="insert into login values(?,?,?)"; 
    BatchPreparedStatementSetter setter=null; 
//使用匿名内部类,实现BatchPreparedStatementSetter接口,实现批量更新
    setter=new BatchPreparedStatementSetter(){ 
        public int getBatchSize(){ 
            return persons.size(); 
        } 
        public void setValues(PreparedStatement ps,int index) throws SQLException{ 
            Person person=(Person)persons.get(index); 
            ps.setString(1,person.getName()); 
            ps.setString(2,person.getPassword()); 
            ps.setString(3,person.getAddress()); 
        } 
    }; 
    return this.getJdbcTemplate().batchUpdate(sql,setter); 
} 
public Person getPersonByRowCallbackHandler(String username){ 
    String sql="select * from login where username=?"; 
    final Person person=new Person(); 
    final Object params[]=new Object[]{username}; 
//使用匿名内部类,实现RowCallbackHandler接口,即实现查询结果集的RowMapping
    this.getJdbcTemplate().query(sql,params,new RowCallbackHandler(){ 
        public void processRow(ResultSet rs)throws SQLException{ 
            person.setName(rs.getString("username")); 
            person.setPassword(rs.getString("passwd")); 
            person.setAddress(rs.getString("address")); 
        } 
    }); 
    return person; 
} 
}

 

2.Spring JdbcTemplate的工作流程:

通过1中的小例子,我们可以总结出SpringJdbcTemplate的工作流程如下:

(1).配置数据源:

Spring中,将管理数据库连接的数据源当作普通Java Bean一样在Spring IoC容器中管理,当应用使用数据源时Spring IoC容器负责初始化数据源。

(2).将数据源注入JdbcTemplate:

JdbcTemplate中dataSource属性用于注入配置的数据源,Spring IoC容器通过依赖注入将配置的数据源注入到Spring对Jdbc操作的封装类JdbcTemplate中。

(3).应用中使用JdbcTemplate:

注入了数据源的JdbcTemplate就可以在应用中使用了,应用中对数据源的增删改查等操作都可以使用JdbcTemplate对外提供的方法操作数据库。

3.JdbcTemplate处理Statement的相关方法实现:

JdbcTemplate的execute方法是JdbcTemplate的核心方法,是JdbcTemplate调用jdbc进行查询,添加,删除和更新操作的基础方法,在execute方法中,主要实现对数据库的基本操作,如:获取数据库连接;根据应用对数据库的需要创建数据库的Statement;对数据库操作进行回调;处理数据库异常;关闭数据库连接等等。JdbcTemplate中有真的Jdbc中StatementPreparedStatement和CallableStatement处理的execute方法,首先我们分析处理Statement的相关方法:

(1).处理Statement的execute方法:

//execute方法执行的是输入的sql语句,且没有返回值的
public void execute(final String sql) throws DataAccessException {
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL statement [" + sql + "]");
		}
	//内部类,实现类StatementCallback和SqlProvider接口,执行sql语句的回调类
		class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
			//JdbcTemplate中真正执行输入的sql语句的地方
			public Object doInStatement(Statement stmt) throws SQLException {
				stmt.execute(sql);
				return null;
			}
			//获取输入的sql语句
			public String getSql() {
				return sql;
			}
		}
		//调用通用的处理静态sql语句的execute方法
		execute(new ExecuteStatementCallback());
	}
//通用的处理静态sql语句
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;
			//如果JdbcTemplate指定了本地连接,则将获取到的数据库连接转换为本地连接
			if (this.nativeJdbcExtractor != null &&
	this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
				conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
			}
			//创建Statement
			stmt = conToUse.createStatement();
			applyStatementSettings(stmt);
			Statement stmtToUse = stmt;
			//如果JdbcTemplate指定了本地连接,则将Statement转换为本地Statement
			if (this.nativeJdbcExtractor != null) {
				stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
			}
	//调用ExecuteStatementCallback类的doInStatement回调方法,执行sql语句
			T result = action.doInStatement(stmtToUse);
			handleWarnings(stmt);
			//返回执行结果
			return result;
		}
		catch (SQLException ex) {
			//产生异常,则关闭Statement
			JdbcUtils.closeStatement(stmt);
			stmt = null;
			//释放数据库连接
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			//将数据库异常封装为Spring异常向调用者抛出
			throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
		}
		finally {
			//关闭Statement,释放数据库连接
			JdbcUtils.closeStatement(stmt);
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

Execute方法是JdbcTemplate执行jdbc操作的核心,其他的方法都是通过调用execute方法来操作数据库。

(2). Statement的查询方法:

JdbcTemplate处理Statement的查询方法有很多,但是其中最基本的方法源码如下:

//静态sql的查询方法,第二个参数ResultSetExtractor是查询结果集转换器,用于处理查//询得到的结果集
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
		Assert.notNull(sql, "SQL must not be null");
		Assert.notNull(rse, "ResultSetExtractor must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL query [" + sql + "]");
		}
	//实现了StatementCallback和SqlProvider接口的内部类,用于execute方法回调
		class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
			//execute方法执行查询操作时回调方法,真正执行jdbc操作的方法
			public T doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = null;
				try {
					//调用Statement的查询方法
					rs = stmt.executeQuery(sql);
					ResultSet rsToUse = rs;
					//如果JdbcTemplate指定了本地jdbc提取器,则将查询得到的结果
//集提取为本地结果集
					if (nativeJdbcExtractor != null) {
						rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
					}
					//使用结果集提取器对查询得到的结果集进行处理
					return rse.extractData(rsToUse);
				}
				finally {
					//关闭结果集
					JdbcUtils.closeResultSet(rs);
				}
			}
			//获取sql
			public String getSql() {
				return sql;
			}
		}
		//调用处理Statement的execute方法
		return execute(new QueryStatementCallback());
	}



(3).Statement的更新方法:

//静态sql的更新方法
	public int update(final String sql) throws DataAccessException {
		Assert.notNull(sql, "SQL must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL update [" + sql + "]");
		}
	//实现了StatementCallback和SqlProvider接口的内部类,Statement
//的execute方法回调
		class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
			//Statement的execute方法更新操作时回调方法,真正执行jdbc操作的方法
			public Integer doInStatement(Statement stmt) throws SQLException {
				//Statement执行jdbc的更新操作,返回影响行数
				int rows = stmt.executeUpdate(sql);
				if (logger.isDebugEnabled()) {
					logger.debug("SQL update affected " + rows + " rows");
				}
				return rows;
			}
			public String getSql() {
				return sql;
			}
		}
		//调用Statement的execute方法
		return execute(new UpdateStatementCallback());
	}


 

通过对Statement相关处理的方法源码分析,我们可以看出execute方法是核心方法,在execute方法中,主要获取数据库连接和创建Statement,同时当执行完jdbc操作之后释放连接和资源等数据库操作的通用流程,所有的查询,更新等具体操作均是通过向execute方法传递合适的回调参数来使用execute方法中的数据库通用流程和资源,真正执行jdbc操作的方法由具体的回调内部类来实现。

4.JdbcTemplate处理PreparedStatement的相关方法实现:

 

(1).处理PreparedStatement的execute方法:

//PreparedStatement处理sql语句的execute方法
public <T> T execute(String sql, PreparedStatementCallback<T> action) throws DataAccessException {
//将sql语句封装成为SimplePreparedStatementCreator,调用处理//PreparedStatement的方法
		return execute(new SimplePreparedStatementCreator(sql), action);
	}
//处理PreparedStatement
public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
			throws DataAccessException {
		Assert.notNull(psc, "PreparedStatementCreator must not be null");
		Assert.notNull(action, "Callback object must not be null");
		if (logger.isDebugEnabled()) {
			String sql = getSql(psc);
			logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
		}
		//获取数据库连接
		Connection con = DataSourceUtils.getConnection(getDataSource());
		PreparedStatement ps = null;
		try {
			Connection conToUse = con;
	    //如果JdbcTemplate指定了jdbc本地提取器,则将获取到的数据库连接转换
//为本地数据库连接
			if (this.nativeJdbcExtractor != null &&
	this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
				conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
			}
			//根据数据库连接和sql语句创建PreparedStatement
			ps = psc.createPreparedStatement(conToUse);
			applyStatementSettings(ps);
			PreparedStatement psToUse = ps;
			//如果JdbcTemplate指定了jdbc本地提取器,则将PreparedStatement转换
//为本地PreparedStatement
			if (this.nativeJdbcExtractor != null) {
				psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
			}
			//调用回调处理器,执行相应操作
			T result = action.doInPreparedStatement(psToUse);
			handleWarnings(ps);
			return result;
		}
		catch (SQLException ex) {
			//关闭资源,释放连接
			if (psc instanceof ParameterDisposer) {
				((ParameterDisposer) psc).cleanupParameters();
			}
			String sql = getSql(psc);
			psc = null;
			JdbcUtils.closeStatement(ps);
			ps = null;
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			//将jdbc相关异常封装转换为Spring异常向调用者抛出
			throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);
		}
		finally {
			//清除PreparedStatement的参数
			if (psc instanceof ParameterDisposer) {
				((ParameterDisposer) psc).cleanupParameters();
			}
			//关闭PreparedStatement
			JdbcUtils.closeStatement(ps);
			//释放数据库连接
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

(2). PreparedStatement的查询方法:

和Statement类似,JdbcTemplate中PreparedStatement的查询方法也非常多,我们以最基本的查询方法源码为例分析其处理流程:

//PreparedStatement查询方法,第一个参数PreparedStatementCreator为封装sql语句的//类,第二个参数PreparedStatementSetter为向PreparedStatement设置参数的类,第三//个参数ResultSetExtractor为处理结果集的类
public <T> T query(
			PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
			throws DataAccessException {
		Assert.notNull(rse, "ResultSetExtractor must not be null");
		logger.debug("Executing prepared SQL query");
//调用PreparedStatement的execute方法,第二个参数为一个实现了//PreparedStatementCallback接口的匿名内部类,被execute回调
		return execute(psc, new PreparedStatementCallback<T>() {
			//执行jdbc操作的方法
			public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
				ResultSet rs = null;
				try {
				//如果PreparedStatement参数不为null,则为PreparedStatement设置参数值
					if (pss != null) {
						pss.setValues(ps);
					}
					//执行jdbc查询操作
					rs = ps.executeQuery();
					ResultSet rsToUse = rs;
			//如果JdbcTemplate指定了本地jdbc提取器,则将查询得到的结果
//集转换为本地jdbc结果集
					if (nativeJdbcExtractor != null) {
						rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
					}
					//使用配置的结果集处理器提取结果集数据
					return rse.extractData(rsToUse);
				}
				finally {
					//关闭结果集
					JdbcUtils.closeResultSet(rs);
					//清除PreparedStatement参数
					if (pss instanceof ParameterDisposer) {
						((ParameterDisposer) pss).cleanupParameters();
					}
				}
			}
		});
	}


(3). PreparedStatement的更新方法:

// PreparedStatement更新方法,第二个参数PreparedStatementSetter为向//PreparedStatement设置参数的类
protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss)
   throws DataAccessException {
  logger.debug("Executing prepared SQL update");
//调用PreparedStatement的execute方法,第二个参数为实现了//PreparedStatementCallback接口的匿名内部类,由PreparedStatement的
//execute方法回调
  return execute(psc, new PreparedStatementCallback<Integer>() {
   //真正执行jdbc操作的方法
   public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException {
    try {
     //为PreparedStatement设置参数值
     if (pss != null) {
      pss.setValues(ps);
     }
     //PreparedStatement调用jdbc的更新操作,返回受影响的行数
     int rows = ps.executeUpdate();
     if (logger.isDebugEnabled()) {
      logger.debug("SQL update affected " + rows + " rows");
     }
     return rows;
    }
    finally {
     //清除PreparedStatement参数
     if (pss instanceof ParameterDisposer) {
      ((ParameterDisposer) pss).cleanupParameters();
     }
    }
   }
  });
 }

通过对PreparedStatement相关处理方法的源码分析,我们可以看到PreparedStatement和Statement的处理流程基本是相同的,不同之处在于PreparedStatement需要处理设置参数值的操作。

5.JdbcTemplate处理CallableStatement的相关方法实现:

(1).处理CallableStatement的execute方法:

//CallableStatement处理给定字符串的
public <T> T execute(String callString, CallableStatementCallback<T> action) throws DataAccessException {
//将字符串封装为SimpleCallableStatementCreator类,调用execute方法处//理CallableStatement
		return execute(new SimpleCallableStatementCreator(callString), action);
	}
//CallableStatement的execute方法,第一个参数CallableStatementCreator是封装调用字//符串的类,封装调用数据库存储过程的语句
public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action)
			throws DataAccessException {
		Assert.notNull(csc, "CallableStatementCreator must not be null");
		Assert.notNull(action, "Callback object must not be null");
		if (logger.isDebugEnabled()) {
			String sql = getSql(csc);
			logger.debug("Calling stored procedure" + (sql != null ? " [" + sql  + "]" : ""));
		}
		//根据数据源获取数据库连接
		Connection con = DataSourceUtils.getConnection(getDataSource());
		CallableStatement cs = null;
		try {
			Connection conToUse = con;
			//如果JdbcTemplate指定了本地jdbc提取器,则将获取到的数据库连接转换为
			//本地数据库连接
			if (this.nativeJdbcExtractor != null) {
				conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
			}
			//根据数据库连接创建CallableStatement
			cs = csc.createCallableStatement(conToUse);
			applyStatementSettings(cs);
			CallableStatement csToUse = cs;
			//如果JdbcTemplate指定了本地jdbc提取器,则将CallableStatement转换为
			//本地CallableStatement
			if (this.nativeJdbcExtractor != null) {
				csToUse = this.nativeJdbcExtractor.getNativeCallableStatement(cs);
			}
			//调用相应回调对象的方法,执行jdbc操作
			T result = action.doInCallableStatement(csToUse);
			handleWarnings(cs);
			return result;
		}
		catch (SQLException ex) {
			//清除CallableStatement参数
			if (csc instanceof ParameterDisposer) {
				((ParameterDisposer) csc).cleanupParameters();
			}
			String sql = getSql(csc);
			csc = null;
			//关闭CallableStatement
			JdbcUtils.closeStatement(cs);
			cs = null;
			//释放数据库连接
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			//将jdbc异常封装为Spring异常
			throw getExceptionTranslator().translate("CallableStatementCallback", sql, ex);
		}
		finally {
			//清除CallableStatement参数
			if (csc instanceof ParameterDisposer) {
				((ParameterDisposer) csc).cleanupParameters();
			}
			//关闭CallableStatement
			JdbcUtils.closeStatement(cs);
			//释放数据库连接
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}


(2).CallableStatementcall方法:

//CallableStatement调用数据库的存储过程
public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)
			throws DataAccessException {
		final List<SqlParameter> updateCountParameters = new ArrayList<SqlParameter>();
		final List<SqlParameter> resultSetParameters = new ArrayList<SqlParameter>();
		final List<SqlParameter> callParameters = new ArrayList<SqlParameter>();
		//遍历声明的参数
		for (SqlParameter parameter : declaredParameters) {
			//如果参数是结果参数
			if (parameter.isResultsParameter()) {
				//如果参数是返回结果集类型,则将参数添加到结果集参数集合中
				if (parameter instanceof SqlReturnResultSet) {
					resultSetParameters.add(parameter);
				}
				//如果参数不是返回结果集类型,则将参数添加到更新数目参数集合中
				else {
					updateCountParameters.add(parameter);				
				}
			}
			//如果参数不是结果参数,则将参数添加到调用参数集合中
			else {
				callParameters.add(parameter);
			}
		}
//调用CallableStatement的execute方法,第二个参数是实现了//CallableStatementCallback接口的匿名内部类,用于回调
		return execute(csc, new CallableStatementCallback<Map<String, Object>>() {
			//真正调用jdbc操作的方法
			public Map<String, Object> doInCallableStatement(CallableStatement cs) throws SQLException {
//CallableStatement执行jdbc调用,如果是返回结果为结果集则为//ture,如果执行返回结果不是结果集则返回false
				boolean retVal = cs.execute();
				//获取CallableStatement执行后数据库中被更新的记录数
				int updateCount = cs.getUpdateCount();
				if (logger.isDebugEnabled()) {
					logger.debug("CallableStatement.execute() returned '" + retVal + "'");
					logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
				}
				//创建一个用于返回指向结果的集合
				Map<String, Object> returnedResults = createResultsMap();
				   //如果CallableStatement执行的返回结果结果是结果集,或者
//CallableStatement执行的更新操作,数据库中有记录被更新
				if (retVal || updateCount != -1) {
					//将存储过程调用结果提取成结果集集合
					returnedResults.putAll(extractReturnedResults(cs, updateCountParameters, resultSetParameters, updateCount));
				}
	//如果CallableStatement执行的返回结果不是结果集,且不是更新操作,
			//则将存储过程的输出参数提取为结果集
				returnedResults.putAll(extractOutputParameters(cs, callParameters));
				return returnedResults;
			}
		});
	}


 

通过上面对CallableStatement相关处理方法的源码分析我们可以看到,execute方法基本和StatementPreparedStatement是相同的,不同之处在于CallableStatement是通过jdbc调用数据库的存储过程,对于输入输出参数的组装,以及返回结果的处理方面有些特殊处理。

6.JdbcTemplate通过DataSourceUtils获取数据库连接:

JdbcTemplate的execute方法中通过DataSourceUtils.getConnection(getDataSource());获取数据库连接,下面我们就分析DataSourceUtils类获取数据库连接的实现过程:

//获取数据库连接的入口方法
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
		try {
			//通过doGetConnection方法来获取数据库连接
			return doGetConnection(dataSource);
		}
		catch (SQLException ex) {
			throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
		}
	}
//获取数据库连接
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
		Assert.notNull(dataSource, "No DataSource specified");
		//把数据库连接放到事务管理器中管理
	//通过TransactionSynchronizationManager中定义的线程局部
//变量(threadlocal)来和线程绑定数据库连接
		ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
	//如果TransactionSynchronizationManager中已有与当前线程绑定的数据库连接
		if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
			//从当前线程线程局部变量中获取数据库连接
			conHolder.requested();
	//如果当前线程局部变量中没有绑定数据库连接,则为当前线程局部变量设置数据库连接
			if (!conHolder.hasConnection()) {
				logger.debug("Fetching resumed JDBC Connection from DataSource");
				conHolder.setConnection(dataSource.getConnection());
			}
	//直接返回TransactionSynchronizationManager线程局部变量中的数据库连接
			return conHolder.getConnection();
		}
		//如果TransactionSynchronizationManager中没有和当前线程绑定的数据
//库连接,则从Spring配置文件配置的数据源对象中获取数据库连接
		logger.debug("Fetching JDBC Connection from DataSource");
		Connection con = dataSource.getConnection();
//如果当前线程事务同步是Active的,即在注册之前可以直接使用,避免不必要
//的实例对象创建
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			logger.debug("Registering transaction synchronization for JDBC Connection");
			//在事务中使用同一个数据库连接做jdbc操作,当事务结束后,线程绑定对象
//将被同步移除 
			ConnectionHolder holderToUse = conHolder;
			//如果存放数据库连接的线程局部变量为null,则重新创建一个线程局部变量
			if (holderToUse == null) {
				holderToUse = new ConnectionHolder(con);
			}
			//如果存放数据库连接的线程局部变量不为null,则将数据库连接存放到线程
//局部变量中
			else {
				holderToUse.setConnection(con);
			}
			//请求数据库连接
			holderToUse.requested();
			//为当前线程注册事务同步
			TransactionSynchronizationManager.registerSynchronization(
					new ConnectionSynchronization(holderToUse, dataSource));
			//标记当前数据库连接为事务同步
			holderToUse.setSynchronizedWithTransaction(true);
			if (holderToUse != conHolder) {
			//将数据源绑定到当前线程局部变量
			TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
			}
		}
		return con;
	}


通过对JdbcTemplate的源码分析,我们看到Spring只是将jdbc的一些常用操作封装,将通用的获取数据库连接、创建创建Statement、关闭资源释放连接等操作封装在不同种类的execute方法中,同时调用不同的回调处理Action来具体执行jdbc操作,对jdbc熟悉的人很容易看懂这部分源码,当然Spring还对jdbc进行了一些高级的封装和扩展,例如RowMapper将结果集转换为指定对象等,这部分有兴趣可以自己研究。




转载地址:http://blog.csdn.net/chjttony/article/details/6404089

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值