Spring(三) spring对jdbc的封装

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;
}


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值