spring技术内幕11-JdbcTemplate封装Jdbc

来源:互联网 发布:dota2多核优化启动项 编辑:程序博客网 时间:2024/06/06 18:45

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将结果集转换为指定对象等。

0 0
原创粉丝点击