1、Spring中使用JdbcTemplate封装对Jdbc的支持,使用Spring Jdbc Template的列子如下:
(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配置文件中添加关于数据源和JdbcTemplate的配置如下:
<?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:mysl://localhost:3360/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.myslq.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)使用JdbcTemplate的DAO如下:
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()
};
reurn 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.setSring(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中的小例子,我们可以总结出Spring JdbcTemplate的工作流程如下:
(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中Statement、PreparedStatement和CallableStatement处理的execute方法,首先我们分析处理Statement的相关方法:
(1)处理Statement的execute方法:
//execute方法执行的是输入的sql语句,且没有返回值的
public void execute(final String sql) thows 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 [" + "]");
}
//实现了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 extecute(String sql,PreparedStatementCallback<T> action) throws DataAccessException{
//将sql语句封装成SimlePreparedStatementCreator,调用处理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.releanseConnection(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.natvieJdbcExtractor.getNatvieCallableStatement(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("CallbalbeStatementCallback",sql,ex);
}
finally{
//清除CallableStatement参数
if(csc instanceof ParameterDisposer){
((ParameterDisposer) csc).cleanupParameters();
}
//关闭CallableStatement
JdbcUtils.closeStatement(cs);
//释放数据库连接
DataSourceUtils.releaseConnection(con,getDataSource());
}
}
(2)CallableStatement的call方法:
//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.isResultParameter()){
//如果参数是返回结果类型,则将参数添加到结果集参数集合中
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调用,如果是返回结果为结果集则为true,如果执行返回结果不是结果集则返回false
boolean retVa = cx.execute();
//获取CallableStatement执行后数据库中被更新的记录数
int updateCount = cs.getUpdateCount();
if(logger.isDebugEnabled()){
logger.debug("CallableStatement.execute() returned '" + retVal + "'");
logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
}
//创建一个用于返回指向结果的集合
Map<String,Object> returnedResult = createResultsMap();
//如果CallableStatement执行的返回结果结果集,或者CallableStatement执行的更新操作,数据库中有记录被更新
if(retVal || updateCount != -1){
//将存储过程调用结果提取成结果集合
returnedResults.putAll(extractReturnedResults(cs,updatCountParameters,resultSetParameters,updateCount));
//如果CallableStatement执行的返回结果不是结果集,且不是更新操作,则将存储过程的输出参数提取为结果集
returnedResults.putAll(extractOutputParameters(cs,callParameters));
return returnedResults;
}
});
}
通过上面对CallableStatement相关处理方法的源码分析我们可以看到,execute方法基本和Statement、PreparedStatement是相同的,不同之处在于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中定义的线程局部变量(thrreadlocal)来和线程绑定数据库连接
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操作。当然Spring还对jdbc进行了一些高价的封装和扩展,例如RowMapper将结果集转换为指定对象等。