`
hlbng
  • 浏览: 177933 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

jdbctemplate源码

阅读更多
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.core.CollectionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.SQLWarningException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.ParameterDisposer;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.ResultSetSupportingSqlParameter;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.jdbc.core.SqlReturnResultSet;
import org.springframework.jdbc.core.SqlRowSetResultSetExtractor;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.jdbc.datasource.ConnectionProxy;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcAccessor;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.util.Assert;

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {

 private static final String RETURN_RESULT_SET_PREFIX = "#result-set-";

 private static final String RETURN_UPDATE_COUNT_PREFIX = "#update-count-";

 private NativeJdbcExtractor nativeJdbcExtractor;

 private boolean ignoreWarnings = true;

 private int fetchSize = 0;

 private int maxRows = 0;

 private int queryTimeout = 0;

 private boolean skipResultsProcessing = false;

 private boolean skipUndeclaredResults = false;

 private boolean resultsMapCaseInsensitive = false;

 public JdbcTemplate() {
 }

 public JdbcTemplate(DataSource dataSource) {
  setDataSource(dataSource);
  afterPropertiesSet();
 }

 public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
  setDataSource(dataSource);
  setLazyInit(lazyInit);
  afterPropertiesSet();
 }

 public void setNativeJdbcExtractor(NativeJdbcExtractor extractor) {
  this.nativeJdbcExtractor = extractor;
 }

 public NativeJdbcExtractor getNativeJdbcExtractor() {
  return this.nativeJdbcExtractor;
 }

 public void setIgnoreWarnings(boolean ignoreWarnings) {
  this.ignoreWarnings = ignoreWarnings;
 }

 public boolean isIgnoreWarnings() {
  return this.ignoreWarnings;
 }

 public void setFetchSize(int fetchSize) {
  this.fetchSize = fetchSize;
 }

 public int getFetchSize() {
  return this.fetchSize;
 }

 public void setMaxRows(int maxRows) {
  this.maxRows = maxRows;
 }

 public int getMaxRows() {
  return this.maxRows;
 }

 public void setQueryTimeout(int queryTimeout) {
  this.queryTimeout = queryTimeout;
 }

 public int getQueryTimeout() {
  return this.queryTimeout;
 }

 public void setSkipResultsProcessing(boolean skipResultsProcessing) {
  this.skipResultsProcessing = skipResultsProcessing;
 }

 public boolean isSkipResultsProcessing() {
  return this.skipResultsProcessing;
 }

 public void setSkipUndeclaredResults(boolean skipUndeclaredResults) {
  this.skipUndeclaredResults = skipUndeclaredResults;
 }

 public boolean isSkipUndeclaredResults() {
  return this.skipUndeclaredResults;
 }

 public void setResultsMapCaseInsensitive(boolean resultsMapCaseInsensitive) {
  this.resultsMapCaseInsensitive = resultsMapCaseInsensitive;
 }

 public boolean isResultsMapCaseInsensitive() {
  return this.resultsMapCaseInsensitive;
 }

 public Object execute(ConnectionCallback action) throws DataAccessException 
 {
  Assert.notNull(action, "Callback object must not be null");

  Connection con = DataSourceUtils.getConnection(getDataSource());
  try {
   Connection conToUse = con;
   if (this.nativeJdbcExtractor != null) {
    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
   }
   else {
    conToUse = createConnectionProxy(con);
   }
   return action.doInConnection(conToUse);
  }
  catch (SQLException ex) {
     DataSourceUtils.releaseConnection(con, getDataSource());
   con = null;
   throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
  }
  finally {
   DataSourceUtils.releaseConnection(con, getDataSource());
  }
 }

 protected Connection createConnectionProxy(Connection con) 
 {
  return (Connection) Proxy.newProxyInstance(
    ConnectionProxy.class.getClassLoader(),
    new Class[] {ConnectionProxy.class},
    new CloseSuppressingInvocationHandler(con));
 }

 public Object execute(StatementCallback 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);
   }
   Object result = action.doInStatement(stmtToUse);
   handleWarnings(stmt.getWarnings());
   return result;
  }
  catch (SQLException ex) 
  {
   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());
  }
 }

 public void execute(final String sql) throws DataAccessException {
  if (logger.isDebugEnabled()) {
   logger.debug("Executing SQL statement [" + sql + "]");
  }

  class ExecuteStatementCallback implements StatementCallback, SqlProvider {
   public Object doInStatement(Statement stmt) throws SQLException {
    stmt.execute(sql);
    return null;
   }
   public String getSql() {
    return sql;
   }
  }
  execute(new ExecuteStatementCallback());
 }

 public Object query(final String sql, final ResultSetExtractor 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 + "]");
  }

  class QueryStatementCallback implements StatementCallback, SqlProvider {
   public Object doInStatement(Statement stmt) throws SQLException {
    ResultSet rs = null;
    try {
     rs = stmt.executeQuery(sql);
     ResultSet rsToUse = rs;
     if (nativeJdbcExtractor != null) {
      rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
     }
     return rse.extractData(rsToUse);
    }
    finally {
     JdbcUtils.closeResultSet(rs);
    }
   }
   public String getSql() {
    return sql;
   }
  }
  return execute(new QueryStatementCallback());
 }

 public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
  query(sql, new RowCallbackHandlerResultSetExtractor(rch));
 }

 public List query(String sql, RowMapper rowMapper) throws DataAccessException {
  return (List) query(sql, new RowMapperResultSetExtractor(rowMapper));
 }

 public Map queryForMap(String sql) throws DataAccessException {
  return (Map) queryForObject(sql, getColumnMapRowMapper());
 }

 public Object queryForObject(String sql, RowMapper rowMapper) throws DataAccessException {
  List results = query(sql, rowMapper);
  return DataAccessUtils.requiredSingleResult(results);
 }

 public Object queryForObject(String sql, Class requiredType) throws DataAccessException {
  return queryForObject(sql, getSingleColumnRowMapper(requiredType));
 }

 public long queryForLong(String sql) throws DataAccessException {
  Number number = (Number) queryForObject(sql, Long.class);
  return (number != null ? number.longValue() : 0);
 }

 public int queryForInt(String sql) throws DataAccessException {
  Number number = (Number) queryForObject(sql, Integer.class);
  return (number != null ? number.intValue() : 0);
 }

 public List queryForList(String sql, Class elementType) throws DataAccessException {
  return query(sql, getSingleColumnRowMapper(elementType));
 }

 public List queryForList(String sql) throws DataAccessException {
  return query(sql, getColumnMapRowMapper());
 }

 public SqlRowSet queryForRowSet(String sql) throws DataAccessException {
  return (SqlRowSet) query(sql, new SqlRowSetResultSetExtractor());
 }

 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 + "]");
  }

  class UpdateStatementCallback implements StatementCallback, SqlProvider {
   public Object doInStatement(Statement stmt) throws SQLException {
    int rows = stmt.executeUpdate(sql);
    if (logger.isDebugEnabled()) {
     logger.debug("SQL update affected " + rows + " rows");
    }
    return new Integer(rows);
   }
   public String getSql() {
    return sql;
   }
  }
  return ((Integer) execute(new UpdateStatementCallback())).intValue();
 }

 public int[] batchUpdate(final String[] sql) throws DataAccessException {
  Assert.notEmpty(sql, "SQL array must not be empty");
  if (logger.isDebugEnabled()) {
   logger.debug("Executing SQL batch update of " + sql.length + " statements");
  }

  class BatchUpdateStatementCallback implements StatementCallback, SqlProvider {
   private String currSql;
   public Object doInStatement(Statement stmt) throws SQLException, DataAccessException {
    int[] rowsAffected = new int[sql.length];
    if (JdbcUtils.supportsBatchUpdates(stmt.getConnection())) {
     for (int i = 0; i < sql.length; i++) {
      this.currSql = sql[i];
      stmt.addBatch(sql[i]);
     }
     rowsAffected = stmt.executeBatch();
    }
    else {
     for (int i = 0; i < sql.length; i++) {
      this.currSql = sql[i];
      if (!stmt.execute(sql[i])) {
       rowsAffected[i] = stmt.getUpdateCount();
      }
      else {
       throw new InvalidDataAccessApiUsageException("Invalid batch SQL statement: " + sql[i]);
      }
     }
    }
    return rowsAffected;
   }
   public String getSql() {
    return currSql;
   }
  }
  return (int[]) execute(new BatchUpdateStatementCallback());
 }

 public Object execute(PreparedStatementCreator psc, PreparedStatementCallback 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;
   if (this.nativeJdbcExtractor != null &&
     this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
   }
   ps = psc.createPreparedStatement(conToUse);
   applyStatementSettings(ps);
   PreparedStatement psToUse = ps;
   if (this.nativeJdbcExtractor != null) {
    psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
   }
   Object result = action.doInPreparedStatement(psToUse);
   handleWarnings(ps.getWarnings());
   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;
   throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);
  }
  finally {
   if (psc instanceof ParameterDisposer) {
    ((ParameterDisposer) psc).cleanupParameters();
   }
   JdbcUtils.closeStatement(ps);
   DataSourceUtils.releaseConnection(con, getDataSource());
  }
 }

 public Object execute(String sql, PreparedStatementCallback action) throws DataAccessException {
  return execute(new SimplePreparedStatementCreator(sql), action);
 }

 public Object query(
   PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)
   throws DataAccessException {

  Assert.notNull(rse, "ResultSetExtractor must not be null");
  logger.debug("Executing prepared SQL query");

  return execute(psc, new PreparedStatementCallback() {
   public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
    ResultSet rs = null;
    try {
     if (pss != null) {
      pss.setValues(ps);
     }
     rs = ps.executeQuery();
     ResultSet rsToUse = rs;
     if (nativeJdbcExtractor != null) {
      rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
     }
     return rse.extractData(rsToUse);
    }
    finally {
     JdbcUtils.closeResultSet(rs);
     if (pss instanceof ParameterDisposer) {
      ((ParameterDisposer) pss).cleanupParameters();
     }
    }
   }
  });
 }

 public Object query(PreparedStatementCreator psc, ResultSetExtractor rse) throws DataAccessException {
  return query(psc, null, rse);
 }

 public Object query(String sql, PreparedStatementSetter pss, ResultSetExtractor rse) throws DataAccessException {
  return query(new SimplePreparedStatementCreator(sql), pss, rse);
 }

 public Object query(String sql, Object[] args, int[] argTypes, ResultSetExtractor rse) throws DataAccessException {
  return query(sql, new ArgTypePreparedStatementSetter(args, argTypes), rse);
 }

 public Object query(String sql, Object[] args, ResultSetExtractor rse) throws DataAccessException {
  return query(sql, new ArgPreparedStatementSetter(args), rse);
 }

 public void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException {
  query(psc, new RowCallbackHandlerResultSetExtractor(rch));
 }

 public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException {
  query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch));
 }

 public void query(String sql, Object[] args, int[] argTypes, RowCallbackHandler rch) throws DataAccessException {
  query(sql, new ArgTypePreparedStatementSetter(args, argTypes), rch);
 }

 public void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException {
  query(sql, new ArgPreparedStatementSetter(args), rch);
 }

 public List query(PreparedStatementCreator psc, RowMapper rowMapper) throws DataAccessException {
  return (List) query(psc, new RowMapperResultSetExtractor(rowMapper));
 }

 public List query(String sql, PreparedStatementSetter pss, RowMapper rowMapper) throws DataAccessException {
  return (List) query(sql, pss, new RowMapperResultSetExtractor(rowMapper));
 }

 public List query(String sql, Object[] args, int[] argTypes, RowMapper rowMapper) throws DataAccessException {
  return (List) query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper));
 }

 public List query(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {
  return (List) query(sql, args, new RowMapperResultSetExtractor(rowMapper));
 }

 public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper)
   throws DataAccessException {

  List results = (List) query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper, 1));
  return DataAccessUtils.requiredSingleResult(results);
 }

 public Object queryForObject(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {
  List results = (List) query(sql, args, new RowMapperResultSetExtractor(rowMapper, 1));
  return DataAccessUtils.requiredSingleResult(results);
 }

 public Object queryForObject(String sql, Object[] args, int[] argTypes, Class requiredType)
   throws DataAccessException {

  return queryForObject(sql, args, argTypes, getSingleColumnRowMapper(requiredType));
 }

 public Object queryForObject(String sql, Object[] args, Class requiredType) throws DataAccessException {
  return queryForObject(sql, args, getSingleColumnRowMapper(requiredType));
 }

 public Map queryForMap(String sql, Object[] args, int[] argTypes) throws DataAccessException {
  return (Map) queryForObject(sql, args, argTypes, getColumnMapRowMapper());
 }

 public Map queryForMap(String sql, Object[] args) throws DataAccessException {
  return (Map) queryForObject(sql, args, getColumnMapRowMapper());
 }

 public long queryForLong(String sql, Object[] args, int[] argTypes) throws DataAccessException {
  Number number = (Number) queryForObject(sql, args, argTypes, Long.class);
  return (number != null ? number.longValue() : 0);
 }

 public long queryForLong(String sql, Object[] args) throws DataAccessException {
  Number number = (Number) queryForObject(sql, args, Long.class);
  return (number != null ? number.longValue() : 0);
 }

 public int queryForInt(String sql, Object[] args, int[] argTypes) throws DataAccessException {
  Number number = (Number) queryForObject(sql, args, argTypes, Integer.class);
  return (number != null ? number.intValue() : 0);
 }

 public int queryForInt(String sql, Object[] args) throws DataAccessException {
  Number number = (Number) queryForObject(sql, args, Integer.class);
  return (number != null ? number.intValue() : 0);
 }

 public List queryForList(String sql, Object[] args, int[] argTypes, Class elementType) throws DataAccessException {
  return query(sql, args, argTypes, getSingleColumnRowMapper(elementType));
 }

 public List queryForList(String sql, Object[] args, Class elementType) throws DataAccessException {
  return query(sql, args, getSingleColumnRowMapper(elementType));
 }

 public List queryForList(String sql, Object[] args, int[] argTypes) throws DataAccessException {
  return query(sql, args, argTypes, getColumnMapRowMapper());
 }

 public List queryForList(String sql, Object[] args) throws DataAccessException {
  return query(sql, args, getColumnMapRowMapper());
 }

 public SqlRowSet queryForRowSet(String sql, Object[] args, int[] argTypes) throws DataAccessException {
  return (SqlRowSet) query(sql, args, argTypes, new SqlRowSetResultSetExtractor());
 }

 public SqlRowSet queryForRowSet(String sql, Object[] args) throws DataAccessException {
  return (SqlRowSet) query(sql, args, new SqlRowSetResultSetExtractor());
 }

 protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss)
   throws DataAccessException {

  logger.debug("Executing prepared SQL update");

  Integer result = (Integer) execute(psc, new PreparedStatementCallback() {
   public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
    try {
     if (pss != null) {
      pss.setValues(ps);
     }
     int rows = ps.executeUpdate();
     if (logger.isDebugEnabled()) {
      logger.debug("SQL update affected " + rows + " rows");
     }
     return new Integer(rows);
    }
    finally {
     if (pss instanceof ParameterDisposer) {
      ((ParameterDisposer) pss).cleanupParameters();
     }
    }
   }
  });
  return result.intValue();
 }

 public int update(PreparedStatementCreator psc) throws DataAccessException {
  return update(psc, (PreparedStatementSetter) null);
 }

 public int update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)
   throws DataAccessException {

  Assert.notNull(generatedKeyHolder, "KeyHolder must not be null");
  logger.debug("Executing SQL update and returning generated keys");

  Integer result = (Integer) execute(psc, new PreparedStatementCallback() {
   public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
    int rows = ps.executeUpdate();
    List generatedKeys = generatedKeyHolder.getKeyList();
    generatedKeys.clear();
    ResultSet keys = ps.getGeneratedKeys();
    if (keys != null) {
     try {
      RowMapper rowMapper = getColumnMapRowMapper();
      RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1);
      generatedKeys.addAll((List) rse.extractData(keys));
     }
     finally {
      JdbcUtils.closeResultSet(keys);
     }
    }
    if (logger.isDebugEnabled()) {
     logger.debug("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys");
    }
    return new Integer(rows);
   }
  });
  return result.intValue();
 }

 public int update(String sql, PreparedStatementSetter pss) throws DataAccessException {
  return update(new SimplePreparedStatementCreator(sql), pss);
 }

 public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
  return update(sql, new ArgTypePreparedStatementSetter(args, argTypes));
 }

 public int update(String sql, Object[] args) throws DataAccessException {
  return update(sql, new ArgPreparedStatementSetter(args));
 }

 public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss) throws DataAccessException {
  if (logger.isDebugEnabled()) {
   logger.debug("Executing SQL batch update [" + sql + "]");
  }

  return (int[]) execute(sql, new PreparedStatementCallback() {
   public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
    try {
     int batchSize = pss.getBatchSize();
     InterruptibleBatchPreparedStatementSetter ipss =
       (pss instanceof InterruptibleBatchPreparedStatementSetter ?
       (InterruptibleBatchPreparedStatementSetter) pss : null);
     if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
      for (int i = 0; i < batchSize; i++) {
       pss.setValues(ps, i);
       if (ipss != null && ipss.isBatchExhausted(i)) {
        break;
       }
       ps.addBatch();
      }
      return ps.executeBatch();
     }
     else {
      List rowsAffected = new ArrayList();
      for (int i = 0; i < batchSize; i++) {
       pss.setValues(ps, i);
       if (ipss != null && ipss.isBatchExhausted(i)) {
        break;
       }
       rowsAffected.add(new Integer(ps.executeUpdate()));
      }
      int[] rowsAffectedArray = new int[rowsAffected.size()];
      for (int i = 0; i < rowsAffectedArray.length; i++) {
       rowsAffectedArray[i] = ((Integer) rowsAffected.get(i)).intValue();
      }
      return rowsAffectedArray;
     }
    }
    finally {
     if (pss instanceof ParameterDisposer) {
      ((ParameterDisposer) pss).cleanupParameters();
     }
    }
   }
  });
 }

 public Object execute(CallableStatementCreator csc, CallableStatementCallback 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;
   if (this.nativeJdbcExtractor != null) {
    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
   }
   cs = csc.createCallableStatement(conToUse);
   applyStatementSettings(cs);
   CallableStatement csToUse = cs;
   if (this.nativeJdbcExtractor != null) {
    csToUse = this.nativeJdbcExtractor.getNativeCallableStatement(cs);
   }
   Object result = action.doInCallableStatement(csToUse);
   handleWarnings(cs.getWarnings());
   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.
   if (csc instanceof ParameterDisposer) {
    ((ParameterDisposer) csc).cleanupParameters();
   }
   String sql = getSql(csc);
   csc = null;
   JdbcUtils.closeStatement(cs);
   cs = null;
   DataSourceUtils.releaseConnection(con, getDataSource());
   con = null;
   throw getExceptionTranslator().translate("CallableStatementCallback", sql, ex);
  }
  finally {
   if (csc instanceof ParameterDisposer) {
    ((ParameterDisposer) csc).cleanupParameters();
   }
   JdbcUtils.closeStatement(cs);
   DataSourceUtils.releaseConnection(con, getDataSource());
  }
 }

 public Object execute(String callString, CallableStatementCallback action) throws DataAccessException {
  return execute(new SimpleCallableStatementCreator(callString), action);
 }

 public Map call(CallableStatementCreator csc, List declaredParameters) throws DataAccessException {
  final List updateCountParameters = new ArrayList();
  final List resultSetParameters = new ArrayList();
  final List callParameters = new ArrayList();
  for (int i = 0; i < declaredParameters.size(); i++) {
   SqlParameter parameter = (SqlParameter) declaredParameters.get(i);
   if (parameter.isResultsParameter()) {
    if (parameter instanceof SqlReturnResultSet) {
     resultSetParameters.add(parameter);
    }
    else {
     updateCountParameters.add(parameter);     
    }
   }
   else {
    callParameters.add(parameter);
   }
  }
  return (Map) execute(csc, new CallableStatementCallback() {
   public Object doInCallableStatement(CallableStatement cs) throws SQLException {
    boolean retVal = cs.execute();
    int updateCount = cs.getUpdateCount();
    if (logger.isDebugEnabled()) {
     logger.debug("CallableStatement.execute() returned '" + retVal + "'");
     logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
    }
    Map returnedResults = createResultsMap();
    if (retVal || updateCount != -1) {
     returnedResults.putAll(extractReturnedResults(cs, updateCountParameters, resultSetParameters, updateCount));
    }
    returnedResults.putAll(extractOutputParameters(cs, callParameters));
    return returnedResults;
   }
  });
 }

 protected Map extractReturnedResults(
   CallableStatement cs, List updateCountParameters, List resultSetParameters, int updateCount)
   throws SQLException {

  Map returnedResults = new HashMap();
  int rsIndex = 0;
  int updateIndex = 0;
  boolean moreResults;
  if (!skipResultsProcessing) {
   do {
    if (updateCount == -1) {
     if (resultSetParameters != null && resultSetParameters.size() > rsIndex) {
      SqlReturnResultSet declaredRsParam = (SqlReturnResultSet)resultSetParameters.get(rsIndex);
      returnedResults.putAll(processResultSet(cs.getResultSet(), declaredRsParam));
      rsIndex++;
     }
     else {
      if (!skipUndeclaredResults) {
       String rsName = RETURN_RESULT_SET_PREFIX + (rsIndex + 1);
       SqlReturnResultSet undeclaredRsParam = new SqlReturnResultSet(rsName, new ColumnMapRowMapper());
       logger.info("Added default SqlReturnResultSet parameter named " + rsName);
       returnedResults.putAll(processResultSet(cs.getResultSet(), undeclaredRsParam));
       rsIndex++;
      }
     }
    }
    else {
     if (updateCountParameters != null && updateCountParameters.size() > updateIndex) {
      SqlReturnUpdateCount ucParam = (SqlReturnUpdateCount)updateCountParameters.get(updateIndex);
      String declaredUcName = ucParam.getName();
      returnedResults.put(declaredUcName, new Integer(updateCount));
      updateIndex++;
     }
     else {
      if (!skipUndeclaredResults) {
       String undeclaredUcName = RETURN_UPDATE_COUNT_PREFIX + (updateIndex + 1);
       logger.info("Added default SqlReturnUpdateCount parameter named " + undeclaredUcName);
       returnedResults.put(undeclaredUcName, new Integer(updateCount));
       updateIndex++;
      }
     }
    }
    moreResults = cs.getMoreResults();
    updateCount = cs.getUpdateCount();
    if (logger.isDebugEnabled()) {
     logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
    }
   }
   while (moreResults || updateCount != -1);
  }
  return returnedResults;
 }

 protected Map extractOutputParameters(CallableStatement cs, List parameters) throws SQLException {
  Map returnedResults = new HashMap();
  int sqlColIndex = 1;
  for (int i = 0; i < parameters.size(); i++) {
   SqlParameter param = (SqlParameter) parameters.get(i);
   if (param instanceof SqlOutParameter) {
    SqlOutParameter outParam = (SqlOutParameter) param;
    if (outParam.isReturnTypeSupported()) {
     Object out = outParam.getSqlReturnType().getTypeValue(
       cs, sqlColIndex, outParam.getSqlType(), outParam.getTypeName());
     returnedResults.put(outParam.getName(), out);
    }
    else {
     Object out = cs.getObject(sqlColIndex);
     if (out instanceof ResultSet) {
      if (outParam.isResultSetSupported()) {
       returnedResults.putAll(processResultSet((ResultSet) out, outParam));
      }
      else {
       String rsName = outParam.getName();
       SqlReturnResultSet rsParam = new SqlReturnResultSet(rsName, new ColumnMapRowMapper());
       returnedResults.putAll(processResultSet(cs.getResultSet(), rsParam));
       logger.info("Added default SqlReturnResultSet parameter named " + rsName);
      }
     }
     else {
      returnedResults.put(outParam.getName(), out);
     }
    }
   }
   if (!(param.isResultsParameter())) {
    sqlColIndex++;
   }
  }
  return returnedResults;
 }

 protected Map processResultSet(ResultSet rs, ResultSetSupportingSqlParameter param) throws SQLException {
  if (rs == null) {
   return Collections.EMPTY_MAP;
  }
  Map returnedResults = new HashMap();
  try {
   ResultSet rsToUse = rs;
   if (this.nativeJdbcExtractor != null) {
    rsToUse = this.nativeJdbcExtractor.getNativeResultSet(rs);
   }
   if (param.getRowMapper() != null) {
    RowMapper rowMapper = param.getRowMapper();
    Object result = (new RowMapperResultSetExtractor(rowMapper)).extractData(rsToUse);
    returnedResults.put(param.getName(), result);
   }
   else if (param.getRowCallbackHandler() != null) {
    RowCallbackHandler rch = param.getRowCallbackHandler();
    (new RowCallbackHandlerResultSetExtractor(rch)).extractData(rsToUse);
    returnedResults.put(param.getName(), "ResultSet returned from stored procedure was processed");
   }
   else if (param.getResultSetExtractor() != null) {
    Object result = param.getResultSetExtractor().extractData(rsToUse);
    returnedResults.put(param.getName(), result);
   }
  }
  finally {
   JdbcUtils.closeResultSet(rs);
  }
  return returnedResults;
 }

 protected RowMapper getColumnMapRowMapper() {
  return new ColumnMapRowMapper();
 }

 protected RowMapper getSingleColumnRowMapper(Class requiredType) {
  return new SingleColumnRowMapper(requiredType);
 }

 protected Map createResultsMap() {
  if (isResultsMapCaseInsensitive()) {
   return CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(10);
  }
  else {
   return new LinkedHashMap();
  }
 }

 protected void applyStatementSettings(Statement stmt) throws SQLException {
  int fetchSize = getFetchSize();
  if (fetchSize > 0) {
   stmt.setFetchSize(fetchSize);
  }
  int maxRows = getMaxRows();
  if (maxRows > 0) {
   stmt.setMaxRows(maxRows);
  }
  DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());
 }

 protected void handleWarnings(SQLWarning warning) throws SQLWarningException {
  if (warning != null) {
   if (isIgnoreWarnings()) {
    if (logger.isDebugEnabled()) {
     SQLWarning warningToLog = warning;
     while (warningToLog != null) {
      logger.debug("SQLWarning ignored: SQL state '" + warningToLog.getSQLState() + "', error code '" +
        warningToLog.getErrorCode() + "', message [" + warningToLog.getMessage() + "]");
      warningToLog = warningToLog.getNextWarning();
     }
    }
   }
   else {
    throw new SQLWarningException("Warning not ignored", warning);
   }
  }
 }

 private static String getSql(Object sqlProvider) {
  if (sqlProvider instanceof SqlProvider) {
   return ((SqlProvider) sqlProvider).getSql();
  }
  else {
   return null;
  }
 }

 private class CloseSuppressingInvocationHandler implements InvocationHandler {

  private final Connection target;

  public CloseSuppressingInvocationHandler(Connection target) {
   this.target = target;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   if (method.getName().equals("getTargetConnection")) {
    return this.target;
   }
   else if (method.getName().equals("equals")) {
    return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
   }
   else if (method.getName().equals("hashCode")) {
    return new Integer(System.identityHashCode(proxy));
   }
   else if (method.getName().equals("close")) {
    return null;
   }
   try {
    Object retVal = method.invoke(this.target, args);
    if (retVal instanceof Statement) {
     applyStatementSettings(((Statement) retVal));
    }
    return retVal;
   }
   catch (InvocationTargetException ex) {
    throw ex.getTargetException();
   }
  }
 }

 private static class SimplePreparedStatementCreator implements PreparedStatementCreator, SqlProvider {

  private final String sql;

  public SimplePreparedStatementCreator(String sql) {
   Assert.notNull(sql, "SQL must not be null");
   this.sql = sql;
  }

  public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
   return con.prepareStatement(this.sql);
  }

  public String getSql() {
   return this.sql;
  }
 }

 private static class SimpleCallableStatementCreator implements CallableStatementCreator, SqlProvider {

  private final String callString;

  public SimpleCallableStatementCreator(String callString) {
   Assert.notNull(callString, "Call string must not be null");
   this.callString = callString;
  }

  public CallableStatement createCallableStatement(Connection con) throws SQLException {
   return con.prepareCall(this.callString);
  }

  public String getSql() {
   return this.callString;
  }
 }

 private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor {

  private final RowCallbackHandler rch;

  public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) {
   this.rch = rch;
  }

  public Object extractData(ResultSet rs) throws SQLException {
   while (rs.next()) {
    this.rch.processRow(rs);
   }
   return null;
  }
 }
}

 

分享到:
评论
2 楼 四个石头 2011-03-28  
哦,我以为是对源码的分析呢
1 楼 hlbng 2009-06-08  
This is the central class in the JDBC core package. It simplifies the use of JDBC and helps to avoid common errors. It executes core JDBC workflow, leaving application code to provide SQL and extract results. This class executes SQL queries or updates, initiating iteration over ResultSets and catching JDBC exceptions and translating them to the generic, more informative exception hierarchy defined in the org.springframework.dao package.

Code using this class need only implement callback interfaces, giving them a clearly defined contract. The PreparedStatementCreator callback interface creates a prepared statement given a Connection, providing SQL and any necessary parameters. The ResultSetExtractor interface extracts values from a ResultSet. See also PreparedStatementSetter and RowMapper for two popular alternative callback interfaces.

Can be used within a service implementation via direct instantiation with a DataSource reference, or get prepared in an application context and given to services as bean reference. Note: The DataSource should always be configured as a bean in the application context, in the first case given to the service directly, in the second case to the prepared template.

Because this class is parameterizable by the callback interfaces and the SQLExceptionTranslator interface, there should be no need to subclass it.

All SQL operations performed by this class are logged at debug level, using "org.springframework.jdbc.core.JdbcTemplate" as log category.

interface PreparedStatementSetter

This interface sets values on a PreparedStatement provided by the JdbcTemplate class, for each of a number of updates in a batch using the same SQL. Implementations are responsible for setting any necessary parameters. SQL with placeholders will already have been supplied.

It's easier to use this interface than PreparedStatementCreator: The JdbcTemplate will create the PreparedStatement, with the callback only being responsible for setting parameter values.

Implementations do not need to concern themselves with SQLExceptions that may be thrown from operations they attempt. The JdbcTemplate class will catch and handle SQLExceptions appropriately.

interface RowCallbackHandler

An interface used by JdbcTemplate for processing rows of a ResultSet on a per-row basis. Implementations of this interface perform the actual work of processing each row but don't need to worry about exception handling. SQLExceptions will be caught and handled by the calling JdbcTemplate.

In contrast to a ResultSetExtractor, a RowCallbackHandler object is typically stateful: It keeps the result state within the object, to be available for later inspection. See RowCountCallbackHandler for a usage example.

Consider using a RowMapper instead if you need to map exactly one result object per row, assembling them into a List.

void processRow(ResultSet rs) throws SQLException

Implementations must implement this method to process each row of data in the ResultSet. This method should not call next() on the ResultSet; it is only supposed to extract values of the current row.

Exactly what the implementation chooses to do is up to it: A trivial implementation might simply count rows, while another implementation might build an XML document.

相关推荐

    spring jdbcTemplate 源码

    本篇将深入探讨Spring JDBCTemplate的使用及其源码解析,帮助你理解其背后的机制。 首先,让我们了解在不使用JDBCTemplate时,传统的JDBC操作通常涉及以下步骤:加载驱动、建立数据库连接、创建Statement或...

    JDBC Template源码.7z

    在源码中,可以看到JdbcTemplate类如何组织这些操作,如`execute()`、`queryForList()`、`update()`等方法。 `PropertyPlaceholderConfigurer`是Spring框架中的一个bean,用于处理属性占位符,如`${property}`。它...

    Spring 学习 JdbcTemplate,模板模式,回调

    在IT行业中,Spring框架是Java开发中的核心工具之一,它为构建企业级应用提供了全面的解决方案。本主题将深入探讨Spring框架中的...在实际项目中,结合源码学习,可以更深入地理解其内部机制,进一步提升开发能力。

    JDBCTemplatejar包和源码

    JDBCTemplatejar包和源码,commons-logging-1.2.jar,spring-beans-5.0.0.RELEASE.jar,spring-core-5.0.0.RELEASE.jar,spring-jdbc-5.0.0.RELEASE.jar,spring-tx-5.0.0.RELEASE.jar

    Struts2+Spring+EasyUI+JDBCTemplate学习源码

    这个学习源码项目是一个完整的运行环境,包含了数据库脚本,意味着你可以导入数据库文件来创建必要的表结构,然后运行项目,观察它们如何协同工作。这将帮助你理解四大技术之间的集成和交互方式,例如,Struts2如何...

    SpringBoot+JPA+JTA(可选)+JdbcTemplate多数据源配置源码

    本资源包含了两个子项目,分别进行了springboot+jpa+jdbcTemplate的多数据源独立事务配置和jta分布式事务配置,并针对不同的情况编写了事务配置测试接口,还演示了JPA的domain一对多自动生成数据库表且不生成数据库...

    基于java+Spring+SpringMVC+JDBCTemplate+JSP开发的博客论坛系统+源码+开发文档+视频演示

    基于java+Spring+SpringMVC+JDBCTemplate+JSP开发的博客论坛系统+源码+开发文档+视频演示,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 基于java+Spring+...

    springmvc JdbcTemplate demo

    JdbcTemplate是Spring框架的一部分,专门用于简化数据库操作,提供了一种模板方法模式来处理SQL语句,使得代码更简洁、可读性更强,同时减少了对低级JDBC API的直接依赖。 SpringMVC与JdbcTemplate的集成是企业级...

    打印JdbcTemplate执行sql

    这篇博客文章的标题"打印JdbcTemplate执行sql"主要涉及如何在使用`JdbcTemplate`时,追踪并打印出执行的SQL语句,这对于调试和性能分析非常有帮助。接下来,我们将深入探讨`JdbcTemplate`的工作原理以及如何实现SQL...

    jdbcTemplate分页彻底解决,使用游标滚动

    在Java的Spring框架中,`JdbcTemplate`是一个非常重要的组件,它...通过阅读和理解`JdbcTemplateExtend.java`和`SplitPageResultSetExtractor.java`的源码,我们可以更深入地了解这一机制,并将其应用到实际项目中。

    jdbcTemplate

    `JdbcTemplate`是Spring框架中的一个核心组件,主要用于简化Java应用程序与关系数据库之间的交互。...通过查看这些源码,我们可以学习到如何在实际项目中优化数据库操作,提升代码的可复用性和可维护性。

    Spring JdbcTemplate 常用方法整理

    Spring的JdbcTemplate是Spring框架中用于简化数据库操作的工具类,它是基于JDBC但又抽象出了一层,避免了直接与数据库驱动API交互,从而提高了代码的可读性和可维护性。本文将深入探讨Spring JdbcTemplate的常用方法...

    SpringBoot用JdbcTemplates访问Mysql实例代码

    在Spring Boot应用中,使用JdbcTemplate访问MySQL数据库是一种常见的数据操作方式。JdbcTemplate是Spring框架提供的一个用于简化JDBC操作的模板类,它提供了一种更安全、更易用的方式来执行SQL语句,同时避免了手动...

    jdbcTemplate-spring对jdbc的支持

    标签"源码"表明可能会涉及JdbcTemplate的内部实现,包括其如何封装JDBC API,以及如何处理异常和事务。源码分析有助于理解其工作原理,以便于进行更高效的定制或扩展。 标签"工具"可能指的是JdbcTemplate作为一个...

    Spring jdbctemplate + mysql 分页封装

    标签"源码"提醒我们关注实现细节,而"工具"可能意味着这种封装可以作为一个工具类供项目中的多个地方使用。在实际开发中,这样的封装能大大提高开发效率,减少重复代码,使得代码更加易于理解和维护。 综上所述,...

    JDBCTemplate+JavaPOJO实现通用DAO

    为了简化JDBC的使用,Spring框架提供了JDBCTemplate,它是一个基于模板方法设计模式的数据库访问类,能够帮助我们更安全、更高效地执行SQL语句。在这个"JDBCTemplate+JavaPOJO实现通用DAO"的项目中,我们将探讨如何...

    JdbcTemplate通用泛型Dao实现

    在Java的Spring框架中,`JdbcTemplate`是一个非常重要的组件,它为数据库操作提供了模板方法,简化了数据库访问。本文将深入探讨`JdbcTemplate`通用泛型Dao实现的相关知识点,帮助开发者更好地理解和应用这一技术。 ...

    spring jdbcTemplate 注入到servlet

    在Java Web开发中,Spring框架提供了丰富的工具来简化数据库操作,其中之一就是`Spring JdbcTemplate`。`JdbcTemplate`是Spring对JDBC(Java Database Connectivity)的一层轻量级封装,它使得开发者能够更加方便地...

    Spring的getBean和JdbcTemplate

    在Java的Spring框架中,`getBean`方法和`JdbcTemplate`是两个核心且重要的概念。它们分别代表了Spring对依赖注入(Dependency Injection,DI)的实现和数据库操作的简化处理。 首先,让我们来深入理解Spring的`...

    Spring-JdbcTemplate

    **Spring-JdbcTemplate 知识详解** `Spring-JdbcTemplate` 是 Spring 框架中的一个核心模块,主要用于简化数据库操作,提供了强大的数据访问功能。它通过模板方法设计模式封装了 SQL 的执行,使得开发者无需直接与 ...

Global site tag (gtag.js) - Google Analytics