设计原理
在Spring JDBC中,JdbcTemplate
是一个主要的模板类,它的类继承关系如图:
从类继承关系上来看,JdbcTemplate
继承了基类JdbcAccessor
和接口类JdbcOperation
。在基类JdbcAccessor的设计中,对DataSource
数据源进行管理和配里。在JdbcOperation接口中,定义了通过JDBC操作数据库的墓本操作方法。而JdbcTemplate提供这些接口方法的实现,比如execute方法、query方法、update方法等。
看JdbcTemplate主要是看excute()
方法和query()
等方法的实现,下面来来一个一个的分析。
JdbcTemplate的execute实现
//这是使用java.sgl.Statement处理静态sql语句的方法
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
//这里取得数据库的Connection,这个数据库的Connection已经在Spring的事务管理之下
Connection con = DataSourceUtils.getConnection(this.getDataSource());
Statement stmt = null;
Object var7;
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
//创建Statement 语句
stmt = conToUse.createStatement();
this.applyStatementSettings(stmt);
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
//这里调用回调函数
T result = action.doInStatement(stmtToUse);
this.handleWarnings(stmt);
var7 = result;
} catch (SQLException var11) {
//如果捕捉到数据库异常.把数据库Connection释放。同时抛出一个经过Spring转换过的Spring数据库异常
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, this.getDataSource());
con = null;
throw this.getExceptionTranslator().translate("StatementCallback", getSql(action), var11);
} finally {
JdbcUtils.closeStatement(stmt);
//释放数据库Connection
DataSourceUtils.releaseConnection(con, this.getDataSource());
}
return var7;
}
//execute方法执行的是输入的SQL语旬,使用的方法类
public void execute(final String sql) throws DataAccessException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Executing SQL statement [" + sql + "]");
}
class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
ExecuteStatementCallback() {
}
public Object doInStatement(Statement stmt) throws SQLException {
stmt.execute(sql);
return null;
}
public String getSql() {
return sql;
}
}
this.execute((StatementCallback)(new ExecuteStatementCallback()));
}
在execute
的实现中看到了对数据库进行操作的基木过程,比如需要取得数据库Connection
,根据应用对数据库操作的需要创建数据库的Statement
,对数据库操作进行回调,处理数据库异常,最后把数据库Connection关闭等。execute方法的设
计时序图如下:
JdbcTemplate的query实现
JdbcTemplate中给出的query
, update
等常用方法的实现,大多都是依抽于前面提到的execute
方法,query的设计时序如下图:
源码如下:
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 (this.logger.isDebugEnabled()) {
this.logger.debug("Executing SQL query [" + sql + "]");
}
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
QueryStatementCallback() {
}
public T doInStatement(Statement stmt) throws SQLException {
//准备结果集
ResultSet rs = null;
Object var4;
try {
//执行Sql查询
rs = stmt.executeQuery(sql);
ResultSet rsToUse = rs;
if (JdbcTemplate.this.nativeJdbcExtractor != null) {
rsToUse = JdbcTemplate.this.nativeJdbcExtractor.getNativeResultSet(rs);
}
//返回需要的结果集记录
var4 = rse.extractData(rsToUse);
} finally {
//关闭操作
JdbcUtils.closeResultSet(rs);
}
return var4;
}
public String getSql() {
return sql;
}
}
return this.execute((StatementCallback)(new QueryStatementCallback()));
}
public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
this.query((String)sql, (ResultSetExtractor)(new JdbcTemplate.RowCallbackHandlerResultSetExtractor(rch)));
}
使用数据库Connection
在以上这些对数据库的操作中,使用了辅助类DataSourceUtils,Spring通过这个辅助类来对数据的Connection进行管理。比如利用它来完成打开和关闭Connection等。DataSourceUtils对这些数据库Connection管理的实现。在数据库应用中,数据库Connection的使用往往与事务管理有很紧密的联系,这里也可以看到与事务处理相关的操作,比如Connection和当前线程的绑定等。源码如下:
//这是取得连接的调用.是通过调用doGetConnection完成的,这里执行了异常的转换操作
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);
} catch (SQLException var2) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", var2);
}
}
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//把对数据库的Connection放到事务管理中进行管理.这里使用在TransactionSynchronizationManager中
//的ThreadLocal来实现线程绑定数据库连接
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
if (conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {
logger.debug("Fetching JDBC Connection from DataSource");
//这里得到有要的数据库Connection,它是在Bean配置文件中定义好的
Connection con = dataSource.getConnection();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
ConnectionHolder holderToUse = conHolder;
if (conHolder == null) {
holderToUse = new ConnectionHolder(con);
} else {
conHolder.setConnection(con);
}
holderToUse.requested();
//数据库连接和线程绑定操作通过TransactionSynchronizationManager来完成
TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
} else {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
}