`
maosheng
  • 浏览: 566072 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring JdbcTemplate源码解析

阅读更多
在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数据库,在JdbcTemplate为用户程序提供了许多便利的数据库操作方法,比如查询,更新等,而且在Spring中,有许多类似JdbcTemplate的模板,比如HibernateTemplate等等。

一般而言这种Template中都是通过回调函数CallBack类的使用来完成功能的,客户需要在回调接口中实现自己需要的定制行为,比如使用客户想要用的SQL语句等。不过往往Spring通过这种回调函数的实现已经为我们提供了许多现成的方法供客户使用。

一般来说回调函数的用法采用匿名类的方式来实现,比如:

JdbcTemplate = new JdbcTemplate(datasource); 

jdbcTemplate.execute(new CallBack(){ 

       public CallbackInterfacedoInAction(){
        //用户定义的代码或者说Spring替我们实现的代码
         .......
        }


在模板中嵌入的是需要客户化的代码,由Spring来作或者需要客户程序亲自动手完成。下面让我们具体看看在JdbcTemplate中的代码是怎样完成使命的,我们举JdbcTemplate.execute()为例,这个方法是在JdbcTemplate中被其他方法调用的基本方法之一,客户程序往往用这个方法来执行基本的SQL语句:
Java代码 
public <T> T execute(ConnectionCallback<T> 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) {
// Extract native JDBC Connection, castable to OracleConnection or the like.
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
else {
// Create close-suppressing Connection proxy, also preparing returned Statements.
conToUse = createConnectionProxy(con);
}

                           //这里调用的是传递进来的匿名类的方法,也就是用户程序需要实现CallBack接口的地方
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.

                           //如果捕捉到数据库异常,把数据库联接释放,同时抛出一个经过Spring转换过的Spring数据库异常
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
}
finally {
                           //最后不管怎样都会把数据库连接释放
DataSourceUtils.releaseConnection(con, getDataSource());
}
}


/**
* Generic callback interface for code that operates on a JDBC Connection.
* Allows to execute any number of operations on a single Connection,
* using any type and number of Statements.
*
* <p>This is particularly useful for delegating to existing data access code
* that expects a Connection to work on and throws SQLException. For newly
* written code, it is strongly recommended to use JdbcTemplate's more specific
* operations, for example a <code>query</code> or <code>update</code> variant.
*
* @author Juergen Hoeller
* @since 1.1.3
* @see JdbcTemplate#execute(ConnectionCallback)
* @see JdbcTemplate#query
* @see JdbcTemplate#update
*/
public interface ConnectionCallback<T> {

/**
* Gets called by <code>JdbcTemplate.execute</code> with an active JDBC
* Connection. Does not need to care about activating or closing the
* Connection, or handling transactions.
*
* <p>If called without a thread-bound JDBC transaction (initiated by
* DataSourceTransactionManager), the code will simply get executed on the
* JDBC connection with its transactional semantics. If JdbcTemplate is
* configured to use a JTA-aware DataSource, the JDBC Connection and thus
* the callback code will be transactional if a JTA transaction is active.
*
* <p>Allows for returning a result object created within the callback, i.e.
* a domain object or a collection of domain objects. Note that there's special
* support for single step actions: see <code>JdbcTemplate.queryForObject</code>
* etc. A thrown RuntimeException is treated as application exception:
* it gets propagated to the caller of the template.
*
* @param con active JDBC Connection
* @return a result object, or <code>null</code> if none
* @throws SQLException if thrown by a JDBC method, to be auto-converted
* to a DataAccessException by a SQLExceptionTranslator
* @throws DataAccessException in case of custom exceptions
* @see JdbcTemplate#queryForObject(String, Class)
* @see JdbcTemplate#queryForRowSet(String)
*/
T doInConnection(Connection con) throws SQLException, DataAccessException;

}


对于JdbcTemplate中给出的其他方法,比如query,update,execute等的实现,我们看看query():

/**
* Query using a prepared statement, allowing for a PreparedStatementCreator
* and a PreparedStatementSetter. Most other query methods use this method,
* but application code will always work with either a creator or a setter.
* @param psc Callback handler that can create a PreparedStatement given a
* Connection
* @param pss object that knows how to set values on the prepared statement.
* If this is null, the SQL will be assumed to contain no bind parameters.
* @param rse object that will extract results.
* @return an arbitrary result object, as returned by the ResultSetExtractor
* @throws DataAccessException if there is any problem
*/
public <T> T query(
PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
throws DataAccessException {

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

                  //这里调用了我们上面看到的execute()基本方法,然而这里的回调实现是Spring为我们完成的查询过程

return execute(psc, new PreparedStatementCallback<T>() {
public T doInPreparedStatement(PreparedStatement ps) throws SQLException {

                                     //准备查询结果集
ResultSet rs = null;
try {
                                              //这里配置SQL参数
if (pss != null) {
pss.setValues(ps);
}
                                             //这里执行的SQL查询
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();
}
}
}
});
}

辅助类DataSourceUtils来用来对数据库连接进行管理的主要工具,比如打开和关闭数据库连接等基本操作:

/**
* Obtain a Connection from the given DataSource. Translates SQLExceptions into
* the Spring hierarchy of unchecked generic data access exceptions, simplifying
* calling code and making any exception that is thrown more meaningful.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link DataSourceTransactionManager}. Will bind a Connection to the
* thread if transaction synchronization is active, e.g. when running within a
* {@link org.springframework.transaction.jta.JtaTransactionManager JTA} transaction).
* @param dataSource the DataSource to obtain Connections from
* @return a JDBC Connection from the given DataSource
* @throws org.springframework.jdbc.CannotGetJdbcConnectionException
* if the attempt to get a Connection failed
* @see #releaseConnection
*/
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
}
}


/**
* Actually obtain a JDBC Connection from the given DataSource.
* Same as {@link #getConnection}, but throwing the original SQLException.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link DataSourceTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
* @param dataSource the DataSource to obtain Connections from
* @return a JDBC Connection from the given DataSource
* @throws SQLException if thrown by JDBC methods
* @see #doReleaseConnection
*/
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对象是怎样得到的?很清楚我们需要在上下文中进行配置:它作为
JdbcTemplate父类JdbcAccessor的属性存在:

/**
* Base class for {@link org.springframework.jdbc.core.JdbcTemplate} and
* other JDBC-accessing DAO helpers, defining common properties such as
* DataSource and exception translator.
*
* <p>Not intended to be used directly.
* See {@link org.springframework.jdbc.core.JdbcTemplate}.
*
* @author Juergen Hoeller
* @since 28.11.2003
* @see org.springframework.jdbc.core.JdbcTemplate
*/
public abstract class JdbcAccessor implements InitializingBean {

/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());

private DataSource dataSource;

private SQLExceptionTranslator exceptionTranslator;

private boolean lazyInit = true;


/**
* Set the JDBC DataSource to obtain connections from.
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

/**
* Return the DataSource used by this template.
*/
public DataSource getDataSource() {
return this.dataSource;
}

     .......

}
分享到:
评论

相关推荐

    spring jdbcTemplate 源码

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

    spring源码深度解析(包含所有spring源码,带全部的注释以及案例,很适合入门级)

    源码深度解析对于开发者来说,是理解Spring工作原理、提升技术水平的重要途径。本资源提供了完整的Spring源码,附带注释和实例,对初学者极其友好。 首先,我们来探讨Spring的核心模块: 1. **IoC容器**:Spring的...

    spring源码

    Spring提供了JdbcTemplate和JPA(Java Persistence API)等工具,简化了数据库操作。Repository接口可以定义数据访问的方法,通过实现这些接口,我们可以定义特定的数据库查询逻辑。 在Spring源码中,可以看到以下...

    spring3.2源码包

    在IoC(Inversion of Control,控制反转)容器方面,Spring 3.2提高了配置文件的解析效率,增强了XML和Java配置的互操作性。它还引入了Profile功能,可以根据不同的运行环境加载不同的配置,增加了应用的可部署性。 ...

    spring 框架源码 版本:5.2.9.RELEASE

    在源码中,你可以看到Repository接口的抽象,以及JdbcTemplate和JPA的实现细节,这有助于理解数据访问的底层逻辑。 Spring还提供了对事务管理的支持,包括编程式和声明式事务。在源码中,你可以看到...

    spring源码分析

    本文将通过对Spring源码的深入解析,逐一探讨这些核心组件的工作原理。 首先,我们关注Spring的事务处理。在Spring中,事务管理是通过声明式和编程式两种方式实现的。声明式事务管理基于XML配置或注解,使得开发者...

    spring源码分析(1-10)

    3. **Spring JDBC**:Spring提供了JdbcTemplate和JpaTemplate等工具类,简化了数据库访问。它们封装了SQL执行和结果集处理,减少了重复代码,提高了可测试性。同时,Spring的数据源管理、事务管理与JDBC紧密结合,...

    Spring源代码解析

    本文将深入解析Spring的源代码,帮助开发者理解其内部机制,提升对框架的使用技巧和定制能力。 首先,Spring的核心模块包括IoC(Inversion of Control,控制反转)容器、AOP、数据访问/集成、Web模块等。IoC容器是...

    Spring Boot实战与原理分析视频课程包含14-18

    --多种数据源的配置、JdbcTemplate、事务的处理 20 Spring Boot AOP 21 Spring Boot Starter18:31 --快速构建自定义的Spring Boot Starter 22 Spring Boot 日志30:58 --演示了如何在Spring Boot里面使用日志配置...

    Spring源代码解析(三):Spring_JDBC.doc

    本篇文章将深入解析Spring JDBC的实现,特别是JdbcTemplate类。JdbcTemplate是Spring为简化数据库操作而设计的一个模板类,它封装了数据库连接获取、SQL执行、异常处理等细节,使开发者可以更专注于业务逻辑。 ...

    spring 3.1的 源码

    7. **Web MVC**:Spring MVC是Spring框架的重要组成部分,3.1版本中增加了对RESTful风格的支持,增强了ModelAndView对象,以及改进了视图解析器。 8. **缓存抽象**:Spring 3.1引入了统一的缓存抽象,支持EhCache、...

    spring 源码解析

    以下是对Spring源码解析的详细知识点: 1. **依赖注入(DI, Dependency Injection)**:Spring通过DI机制管理对象的生命周期和依赖关系,使得组件之间解耦。源码中,`ApplicationContext`是DI的主要实现,通过`...

    spring3.0 源码

    同时,Spring的DAO支持类如JdbcTemplate和HibernateTemplate提供了更方便的数据库操作接口。 五、RESTful支持 Spring 3.0引入了对RESTful风格API的支持,可以通过`@ResponseBody`和`@RequestBody`注解进行HTTP请求...

    spring5源码分析笔记

    Spring的JdbcTemplate和JPA提供了一致的编程模型,简化数据库操作。 7. **Spring MVC**:Spring的Model-View-Controller架构用于构建Web应用程序。DispatcherServlet作为前端控制器,接收请求并分发到相应的处理器...

    spring4.0源码

    - **MVC**:Spring MVC在4.0中得到了显著增强,例如支持RESTful风格的URL路由,改进了视图解析,以及支持HTTP/2和WebSocket。 - **JSON支持**:对Jackson库的集成加强,支持更方便的JSON序列化和反序列化。 - **...

    Spring学习笔记&源码

    本资料“Spring学习笔记&源码”是基于网易云课堂黑马程序员的Spring四天精通课程,旨在帮助学习者深入理解和实践Spring框架。 笔记部分可能会涵盖以下内容: 1. **Spring概述**:介绍Spring框架的历史、特点和主要...

    spring4源码

    - **数据访问**:深入 Hibernate 和 JdbcTemplate 模块,理解 Spring 如何与 ORM 工具集成,提供数据访问抽象。 - **模块化设计**:Spring 框架由多个模块组成,如 Core Container、Data Access/Integration、Web、...

    spring3.2.0源码

    在源码中,我们可以看到`BeanFactory`和`ApplicationContext`接口如何实现对bean的生命周期管理和依赖解析。 2. **AOP(面向切面编程)**: Spring 3.2.0加强了AOP支持,允许开发者定义和执行横切关注点,如日志...

Global site tag (gtag.js) - Google Analytics