dingfirst

On the Road

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  8 随笔 :: 2 文章 :: 3 评论 :: 0 Trackbacks
spring的JdbcTemplate封装了jdbc的实现,下面通过源代码看一下其实现

1,一个执行Statement回调的接口
public interface StatementCallback {
      Object doInStatement(Statement stmt) 
throws SQLException, DataAccessException;
    }

  
public Object execute(StatementCallback action) throws DataAccessException {
      
//获取线程的同一个连接
      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();
          
//计算并调用stmt.setQueryTimeout(..)
          DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
          Statement stmtToUse 
= stmt;
          
if (this.nativeJdbcExtractor != null{
              stmtToUse 
= this.nativeJdbcExtractor.getNativeStatement(stmt);
          }

          
//执行回调
          Object result = action.doInStatement(stmtToUse);
          SQLWarning warning 
= stmt.getWarnings();
          throwExceptionOnWarningIfNotIgnoringWarnings(warning);
          
return result;
      }
 catch (SQLException ex) {
          
//对异常进行转译,所有抛出异常都继承DataAccessException这个非受控异常
          throw getExceptionTranslator().translate(
                  
"executing StatementCallback", getSql(action), ex);
      }
 finally {
          JdbcUtils.closeStatement(stmt);
          DataSourceUtils.releaseConnection(con, getDataSource());
      }

  }

2,一个StatementCallback预定义实现,提供query接口
public Object query(final String sql, final ResultSetExtractor rse) throws DataAccessException {
   
if (sql == null{
          
throw new InvalidDataAccessApiUsageException("SQL must not be null");
      }

      
if (JdbcUtils.countParameterPlaceholders(sql, '?'"'\"") > 0) {
          throw new InvalidDataAccessApiUsageException(
                  
"Cannot execute [" + sql +
                  
"] as a static query: it contains bind variables");
      }

      
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 {
                  
if (getFetchSize() > 0{
                      stmt.setFetchSize(getFetchSize());
                  }

                  
if (getMaxRows() > 0{
                      stmt.setMaxRows(getMaxRows());
                  }

                  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());
  }
3,看一下一个预定义的ResultSetExtractor实现
  private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor {

        
private final RowCallbackHandler rch;

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


        
public Object extractData(ResultSet rs) throws SQLException {
            
//利用RowCallbackHandler处理resultset,返回处理结果List
            while (rs.next()) {
                
this.rch.processRow(rs);
            }

            
if (this.rch instanceof ResultReader) {
                
return ((ResultReader) this.rch).getResults();
            }

            
else {
                
return null;
            }

        }

    }

    
    
public interface ResultReader extends RowCallbackHandler {
     
        
/**
         * Return all results, disconnected from the JDBC ResultSet.
         * Never returns null; returns the empty collection if there
         * were no results.
         
*/

        List getResults();

    }

    
    
    
public class RowMapperResultReader implements ResultReader {

        
/** List to save results in */
        
private final List results;
    
        
/** The RowMapper implementation that will be used to map rows */
        
private final RowMapper rowMapper;
    
        
/** The counter used to count rows */
        
private int rowNum = 0;
    
        
/**
         * Create a new RowMapperResultReader.
         * 
@param rowMapper the RowMapper which creates an object for each row
         
*/

        
public RowMapperResultReader(RowMapper rowMapper) {
            
this(rowMapper, 0);
        }

    
        
/**
         * Create a new RowMapperResultReader.
         * 
@param rowMapper the RowMapper which creates an object for each row
         * 
@param rowsExpected the number of expected rows
         * (just used for optimized collection handling)
         
*/

        
public RowMapperResultReader(RowMapper rowMapper, int rowsExpected) {
            
// Use the more efficient collection if we know how many rows to expect:
            
// ArrayList in case of a known row count, LinkedList if unknown
            this.results = (rowsExpected > 0? (List) new ArrayList(rowsExpected) : (List) new LinkedList();
            
this.rowMapper = rowMapper;
        }

    
        
public void processRow(ResultSet rs) throws SQLException {
            
this.results.add(this.rowMapper.mapRow(rs, this.rowNum++));
        }

    
        
public List getResults() {
            
return this.results;
        }


    }
 4,连接是如何获取的
    public abstract class DataSourceUtils {
        
        
//..
        
        
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
            Assert.notNull(dataSource, 
"No DataSource specified");
            
//利用ThreadLocal,获取当前线程对应dataSource的connection封装---ConnectionHolder
            ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
            
if (conHolder != null{
                conHolder.requested();
                
return conHolder.getConnection();
            }

            
//如果conHolder为空,为当前线程获取一个新连接,并设置ThreadLocal
            logger.debug("Opening JDBC Connection");
            Connection con 
= dataSource.getConnection();
            
            
if (TransactionSynchronizationManager.isSynchronizationActive()) {
                logger.debug(
"Registering transaction synchronization for JDBC Connection");
                
// Use same Connection for further JDBC actions within the transaction.
                
// Thread-bound object will get removed by synchronization at transaction completion.
                conHolder = new ConnectionHolder(con);
                conHolder.setSynchronizedWithTransaction(
true);
                conHolder.requested();
                TransactionSynchronizationManager.registerSynchronization(
                        
new ConnectionSynchronization(conHolder, dataSource));
                TransactionSynchronizationManager.bindResource(dataSource, conHolder);
            }

    
            
return con;
        }

        
//注意异常的改变
        public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
            
try {
                
return doGetConnection(dataSource);
            }

            
catch (SQLException ex) {
                
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
            }

        }

    }
5,getResource和bindResource实现
    public abstract class TransactionSynchronizationManager {
        
        
//..
        
        
private static final ThreadLocal resources = new ThreadLocal();

        
private static final ThreadLocal synchronizations = new ThreadLocal();
        
        
public static Object getResource(Object key) {
            Map map 
= (Map) resources.get();
            
if (map == null{
                
return null;
            }

            Object value 
= map.get(key);
            
if (value != null && logger.isDebugEnabled()) {
                logger.debug(
"Retrieved value [" + value + "] for key [" + key + "] bound to thread [" +
                        Thread.currentThread().getName() 
+ "]");
            }

            
return value;
        }

        
public static void bindResource(Object key, Object value) throws IllegalStateException {
            Map map 
= (Map) resources.get();
            
// set ThreadLocal Map if none found
            if (map == null{
                map 
= new HashMap();
                resources.set(map);
            }

            
if (map.containsKey(key)) {
                
throw new IllegalStateException("Already value [" + map.get(key) + "] for key [" + key +
                        
"] bound to thread [" + Thread.currentThread().getName() + "]");
            }

            map.put(key, value);
            
if (logger.isDebugEnabled()) {
                logger.debug(
"Bound value [" + value + "] for key [" + key + "] to thread [" +
                        Thread.currentThread().getName() 
+ "]");
            }

        }

    }

6,ConnectionHolder 类

public class ConnectionHolder extends ResourceHolderSupport {

    
private final ConnectionHandle connectionHandle;

    
private Connection currentConnection;

    
/**
     * Create a new ConnectionHolder for the given ConnectionHandle.
     * 
@param connectionHandle the ConnectionHandle to hold
     
*/

    
public ConnectionHolder(ConnectionHandle connectionHandle) {
        
this.connectionHandle = connectionHandle;
    }


    
/**
     * Create a new ConnectionHolder for the given JDBC Connection,
     * wrapping it with a SimpleConnectionHandle.
     * 
@param connection the JDBC Connection to hold
     * 
@see SimpleConnectionHandle
     
*/

    
public ConnectionHolder(Connection connection) {
        
this.connectionHandle = new SimpleConnectionHandle(connection);
    }


    
/**
     * Return the ConnectionHandle held by this ConnectionHolder.
     
*/

    
public ConnectionHandle getConnectionHandle() {
        
return connectionHandle;
    }


    
/**
     * Return the current Connection held by this ConnectionHolder.
     * <p>This will be the same Connection until <code>released</code>
     * gets called on the ConnectionHolder, which will reset the
     * held Connection, fetching a new Connection on demand.
     * 
@see ConnectionHandle#getConnection()
     * 
@see #released()
     
*/

    
public Connection getConnection() {
        
if (this.currentConnection == null{
            
this.currentConnection = this.connectionHandle.getConnection();
        }

        
return this.currentConnection;
    }


    
/**
     * Releases the current Connection held by this ConnectionHolder.
     * <p>This is necessary for ConnectionHandles that expect "Connection borrowing",
     * where each returned Connection is only temporarily leased and needs to be
     * returned once the data operation is done, to make the Connection available
     * for other operations within the same transaction. This is the case with
     * JDO 2.0 DataStoreConnections, for example.
     * 
@see org.springframework.orm.jdo.DefaultJdoDialect#getJdbcConnection
     
*/

    
public void released() {
        
super.released();
        
if (this.currentConnection != null{
            
this.connectionHandle.releaseConnection(this.currentConnection);
            
this.currentConnection = null;
        }

    }


}

public class SimpleConnectionHandle implements ConnectionHandle {

    
private final Connection connection;

    
/**
     * Create a new SimpleConnectionHandle for the given Connection.
     * 
@param connection the JDBC Connection
     
*/

    
public SimpleConnectionHandle(Connection connection) {
        
this.connection = connection;
    }


    
public Connection getConnection() {
        
return connection;
    }


    
public void releaseConnection(Connection con) {
    }


    
public String toString() {
        
return "SimpleConnectionHandle: " + this.connection;
    }


}
posted on 2006-07-13 10:39 dingfirst 阅读(1480) 评论(1)  编辑  收藏

评论

# re: spring对jdbc的封装 2006-10-24 12:55 111
11111  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: