标签:
?Spring JDBC采用模板的设计模式来完成设计。抽象类中定义模板方法,在模板方法中对处理过程进行描述,然后每个具体的过程实现则交由子类来实现。
1,设计原理
?在Spring JDBC中,JdbcTemplate是一个主要的模板类,该类继承JdbcAccessor,实现JdbcOperation接口。
?在JdbcAccessor中对DataSource进行管和配置。
?JdbcOperation接口则定义了操作数据库的基本方法。
2,JdbcTemplate的基本使用
?使用JdbcTemplate,可以直接进行对数据库操作的调用,忽略异常处理以及建立连接,数据结果处理等一系列操作。
3,JdbcTemplate的execute实现。
如下为JdbcTemplate的execute方法源码:
@Overridepublic void execute(final String sql) throws DataAccessException {if (logger.isDebugEnabled()) {logger.debug("Executing SQL statement [" + sql + "]");}class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {@Overridepublic Object doInStatement(Statement stmt) throws SQLException {//重写stmt.execute(sql);return null;}@Overridepublic String getSql() {return sql;}}execute(new ExecuteStatementCallback());}
@Overridepublic <T> T execute(StatementCallback<T> action) throws DataAccessException {Assert.notNull(action, "Callback object must not be null");Connection con = DataSourceUtils.getConnection(getDataSource());//获取COnnectionStatement stmt = null;try {Connection conToUse = con;if (this.nativeJdbcExtractor != null &&this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {conToUse = this.nativeJdbcExtractor.getNativeConnection(con);}stmt = conToUse.createStatement();//StatementapplyStatementSettings(stmt);Statement stmtToUse = stmt;if (this.nativeJdbcExtractor != null) {stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);}T result = action.doInStatement(stmtToUse);//调用传入接口的子类的实现handleWarnings(stmt);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.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());}}
4,JdbcTemplate的query方法
@Overridepublic <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 + "]");}class QueryStatementCallback implements StatementCallback<T>, SqlProvider {@Overridepublic T 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);}}@Overridepublic String getSql() {return sql;}}return execute(new QueryStatementCallback());}
我们查看在execute方法中的,发现最终调用的是doInStatement,该方法均在内部类中重写。
5,使用Connection。
?Spring通过DataSourceUtils对Connection进行管理。在数据库应用中,数据库的Connection的使用往往和事务处理相关。
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {try {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");ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);//如果已经存在与当前线程绑定的数据源,则直接取出if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {conHolder.requested();if (!conHolder.hasConnection()) {logger.debug("Fetching resumed JDBC Connection from DataSource");conHolder.setConnection(dataSource.getConnection());}return conHolder.getConnection();}// Else we either got no holder or an empty thread-bound holder here.logger.debug("Fetching JDBC Connection from DataSource");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.ConnectionHolder holderToUse = conHolder;if (holderToUse == null) {holderToUse = new ConnectionHolder(con);}else {holderToUse.setConnection(con);}holderToUse.requested();TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction(true);if (holderToUse != conHolder) {TransactionSynchronizationManager.bindResource(dataSource, holderToUse);}}return con;}
具体的dataSource对象则通过IoC容器实现注入。
?1,SqlQuery的实现
?Spring除了提供基本操作外,还提供一些O/R映射基本,比如MappingSqlQuery。在代码中,我们往往实现自己的类来实现数据库到POJO的映射,具体的实现省略。
?
public abstract class MappingSqlQuery<T> extends MappingSqlQueryWithParameters<T> {/*** Constructor that allows use as a JavaBean.*/public MappingSqlQuery() {}/*** Convenient constructor with DataSource and SQL string.* @param ds DataSource to use to obtain connections* @param sql SQL to run*/public MappingSqlQuery(DataSource ds, String sql) {super(ds, sql);}/*** This method is implemented to invoke the simpler mapRow* template method, ignoring parameters.* @see #mapRow(ResultSet, int)*/@Overrideprotected final T mapRow(ResultSet rs, int rowNum, Object[] parameters, Map<?, ?> context)throws SQLException {return mapRow(rs, rowNum);}/*** Subclasses must implement this method to convert each row of the* ResultSet into an object of the result type.* <p>Subclasses of this class, as opposed to direct subclasses of* MappingSqlQueryWithParameters, don‘t need to concern themselves* with the parameters to the execute method of the query object.* @param rs ResultSet we‘re working through* @param rowNum row number (from 0) we‘re up to* @return an object of the result type* @throws SQLException if there‘s an error extracting data.* Subclasses can simply not catch SQLExceptions, relying on the* framework to clean up.*/protected abstract T mapRow(ResultSet rs, int rowNum) throws SQLException;}
以RdbmsOperation为例。
public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException {if (isCompiled()) {throw new InvalidDataAccessApiUsageException("Cannot add parameters once the query is compiled");}this.declaredParameters.add(param);}
private final List<SqlParameter> declaredParameters = new LinkedList<SqlParameter>();
查看对应的compile操作
/*** Compile this query.* Ignores subsequent attempts to compile.* @throws InvalidDataAccessApiUsageException if the object hasn‘t* been correctly initialized, for example if no DataSource has been provided*/public final void compile() throws InvalidDataAccessApiUsageException {if (!isCompiled()) {if (getSql() == null) {throw new InvalidDataAccessApiUsageException("Property ‘sql‘ is required");}try {this.jdbcTemplate.afterPropertiesSet();}catch (IllegalArgumentException ex) {throw new InvalidDataAccessApiUsageException(ex.getMessage());}compileInternal();this.compiled = true;if (logger.isDebugEnabled()) {logger.debug("RdbmsOperation with SQL [" + getSql() + "] compiled");}}}
compileInternal操作在SqlOperation中完成。
* Overridden method to configure the PreparedStatementCreatorFactory* based on our declared parameters.*/@Overrideprotected final void compileInternal() {this.preparedStatementFactory = new PreparedStatementCreatorFactory(getSql(), getDeclaredParameters());this.preparedStatementFactory.setResultSetType(getResultSetType());this.preparedStatementFactory.setUpdatableResults(isUpdatableResults());this.preparedStatementFactory.setReturnGeneratedKeys(isReturnGeneratedKeys());if (getGeneratedKeysColumnNames() != null) {this.preparedStatementFactory.setGeneratedKeysColumnNames(getGeneratedKeysColumnNames());}this.preparedStatementFactory.setNativeJdbcExtractor(getJdbcTemplate().getNativeJdbcExtractor());onCompileInternal();}
在compile之后,执行查询时,执行的是SqlQuery的executeByNamedParam方法。
public List<T> executeByNamedParam(Map<String, ?> paramMap, Map<?, ?> context) throws DataAccessException {validateNamedParameters(paramMap);ParsedSql parsedSql = getParsedSql();//获取到要执行的sqlMapSqlParameterSource paramSource = new MapSqlParameterSource(paramMap);
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
//配置好sql需要的parameter及RowMapperObject[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, getDeclaredParameters());
RowMapper<T> rowMapper = newRowMapper(params, context);
//JdbcTemplate进行查询return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, params), rowMapper);}
以上就是基本的源码。其中还涉及到一些我们常用的其他源码,以及对Hibernate的封装。个人觉得Hibernate过于繁琐,以及HQL语句对sql的疯转反而过于严重,不是很喜欢,所以对Spring 对Hibernate的源码块跳过。
ps:?Spring对数据库JdbcTemplate的封装较为简单。终于不再像看IoC和AOP那样子晕了。
?
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/mergades/article/details/46853099