`
san_yun
  • 浏览: 2639260 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Spring JdbcTemplate执行过程分析

 
阅读更多

调用入口

调用JdbcTemplate提供的API都会委托给execute(),代码如下:

public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
		throws DataAccessException {

	Assert.notNull(psc, "PreparedStatementCreator must not be null");
	Assert.notNull(action, "Callback object must not be null");
	if (logger.isDebugEnabled()) {
		String sql = getSql(psc);
		logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
	}

	Connection con = DataSourceUtils.getConnection(getDataSource());
	PreparedStatement ps = null;
	try {
		Connection conToUse = con;
		if (this.nativeJdbcExtractor != null &&
				this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
			conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
		}
		ps = psc.createPreparedStatement(conToUse);
		applyStatementSettings(ps);
		PreparedStatement psToUse = ps;
		if (this.nativeJdbcExtractor != null) {
			psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
		}
		T result = action.doInPreparedStatement(psToUse);
		handleWarnings(ps);
		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.
		if (psc instanceof ParameterDisposer) {
			((ParameterDisposer) psc).cleanupParameters();
		}
		String sql = getSql(psc);
		psc = null;
		JdbcUtils.closeStatement(ps);
		ps = null;
		DataSourceUtils.releaseConnection(con, getDataSource());
		con = null;
		throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);
	}
	finally {
		if (psc instanceof ParameterDisposer) {
			((ParameterDisposer) psc).cleanupParameters();
		}
		JdbcUtils.closeStatement(ps);
		DataSourceUtils.releaseConnection(con, getDataSource());
	}
}

 

总结一下可以分为三个步骤:

  1. 获取DataSource的Connection 。
  2. 设置Statement的属性并执行SQL 。
  3. 关闭Connection 。

1.获取Connection

Spring jdbcTemplate 获取Connection 是委托给 DataSourceUtils.getConnection(getDataSource());实现的。里面的核心方法就是调用 dataSource.getConnection()获取。
DBCP的getConnection() 内部是通过GenericObjectPool实现的,PoolableConnectionFactory是pool的工厂负责makeObject():

class BasicDataSource{
    protected void createConnectionPool() {
        // Create an object pool to contain our active connections
        GenericObjectPool gop;
        if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
            gop = new AbandonedObjectPool(null,abandonedConfig);
        }
        else {
            gop = new GenericObjectPool();
        }
        gop.setMaxActive(maxActive);
        gop.setMaxIdle(maxIdle);
        gop.setMinIdle(minIdle);
        gop.setMaxWait(maxWait);
        gop.setTestOnBorrow(testOnBorrow);
        gop.setTestOnReturn(testOnReturn);
        gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        gop.setTestWhileIdle(testWhileIdle);
        connectionPool = gop;
    }
}

 

2.设置Statement的属性并执行SQL

jdbcTempate有一行比较重要的代码applyStatementSettings(ps) 是设置StatementSettings的,包括FetchSize,MaxRows,QueryTimeout等,在某些情况下非常有用。

protected void applyStatementSettings(Statement stmt) throws SQLException {
		int fetchSize = getFetchSize();
		if (fetchSize > 0) {
			stmt.setFetchSize(fetchSize);
		}
		int maxRows = getMaxRows();
		if (maxRows > 0) {
			stmt.setMaxRows(maxRows);
		}
		DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());
	}

 

3.关闭Connection

执行完SQL之后需要关闭connection,jdbcTempalte是委托给 DataSourceUtils.releaseConnection(con, getDataSource()),最核心还是con.close()

public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException {
	if (con == null) {
		return;
	}

	if (dataSource != null) {
		ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
		if (conHolder != null && connectionEquals(conHolder, con)) {
			// It's the transactional Connection: Don't close it.
			conHolder.released();
			return;
		}
	}

	// Leave the Connection open only if the DataSource is our
	// special SmartDataSoruce and it wants the Connection left open.
	if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
		logger.debug("Returning JDBC Connection to DataSource");
		con.close();
	}
}

 

在dbcp中con实际上是PoolableConnection,其close方法被重写只是把connection返回到pool,没有实际关闭。

  public synchronized void close() throws SQLException {
        if (_closed) {
            // already closed
            return;
        }

        boolean isUnderlyingConectionClosed;
        try {
            isUnderlyingConectionClosed = _conn.isClosed();
        } catch (SQLException e) {
            try {
                _pool.invalidateObject(this); // XXX should be guarded to happen at most once
            } catch(IllegalStateException ise) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch (Exception ie) {
                // DO NOTHING the original exception will be rethrown
            }
            throw (SQLException) new SQLException("Cannot close connection (isClosed check failed)").initCause(e);
        }

        if (!isUnderlyingConectionClosed) {
            // Normal close: underlying connection is still open, so we
            // simply need to return this proxy to the pool
            try {
                _pool.returnObject(this); // XXX should be guarded to happen at most once
            } catch(IllegalStateException e) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch(SQLException e) {
                throw e;
            } catch(RuntimeException e) {
                throw e;
            } catch(Exception e) {
                throw (SQLException) new SQLException("Cannot close connection (return to pool failed)").initCause(e);
            }
        } else {
            // Abnormal close: underlying connection closed unexpectedly, so we
            // must destroy this proxy
            try {
                _pool.invalidateObject(this); // XXX should be guarded to happen at most once
            } catch(IllegalStateException e) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch (Exception ie) {
                // DO NOTHING, "Already closed" exception thrown below
            }
            throw new SQLException("Already closed.");
        }
    }

 

分享到:
评论

相关推荐

    SpringJdbcTemplate封装工具类

    SpringJdbcTemplate是一个模板类,它提供了大量的方法来执行SQL查询、更新、存储过程等操作。这些方法会自动处理JDBC相关的资源关闭、异常转换等细节,使得代码更加整洁和健壮。 2. **数据库自适应** Spring...

    打印JdbcTemplate执行sql

    这篇博客文章的标题"打印JdbcTemplate执行sql"主要涉及如何在使用`JdbcTemplate`时,追踪并打印出执行的SQL语句,这对于调试和性能分析非常有帮助。接下来,我们将深入探讨`JdbcTemplate`的工作原理以及如何实现SQL...

    Java图书管理系统( Spring+Spring MVC+JdbcTemplate)

    JdbcTemplate是Spring框架提供的一个简化数据库操作的工具,它降低了与数据库交互的复杂性,允许开发者使用简单的API来执行SQL语句。在这个系统中,JdbcTemplate被用来执行添加、删除、修改和查询图书等数据库操作,...

    JdbcTemplate的事务控制.docx

    如果在执行过程中发生了异常,比如主键冲突导致的插入失败,那么所有操作都将被回滚。 #### 五、总结 通过上述分析可以看出,无论是使用原生JDBC还是结合Spring框架的`JdbcTemplate`,事务控制都是一个关键的步骤...

    jdbctemplatedemo.zip

    综上所述,"jdbctemplatedemo.zip"项目演示了如何使用Spring Boot的JdbcTemplate来高效地处理大批量数据的导出和导入,这是在现代Web应用程序中常见的需求,尤其是在数据分析、报表生成或数据迁移场景下。...

    配置JdbcTemplate

    本篇文章将深入讲解如何配置JdbcTemplate,并通过源代码分析其工作原理。 1. **引入依赖** 首先,你需要在项目中引入Spring JDBC模块的依赖。如果你使用的是Maven,可以在pom.xml文件中添加以下依赖: ```xml ...

    spring-jdbc.rar源码 学习分析用

    JdbcTemplate是Spring提供的一个抽象层,它简化了数据库访问,通过预编译SQL语句、异常转换等功能,避免了手动处理JDBC的繁琐步骤。在源码中,我们可以看到JdbcTemplate是如何通过PreparedStatement和Statement执行...

    Spring框架+jdbTemplete+mysql增删查改

    通过对这些代码的分析,可以深入理解Spring如何整合JdbcTemplate与MySQL,以及如何进行数据操作的实现。 7. **测试与调试**:使用JUnit或Spring Boot的Test slicing功能,可以编写单元测试来验证数据操作的正确性。...

    基于 Spring、SpringMVC、JDBCTemplate、JSP的博客论坛系统 - 毕业设计.zip

    JDBCTemplate是Spring框架中的数据访问组件,它简化了与数据库的交互,提供了模板方法来执行SQL查询和更新操作,避免了手动管理连接、事务和异常处理等繁琐工作。通过使用JDBCTemplate,开发者可以更专注于SQL语句的...

    mysql-jdbc-Spring源代码分析

    4. **异常处理**:如果执行过程中发生`SQLException`,则会通过`DataSourceUtils.releaseConnection()`方法关闭连接,并将异常转换为Spring的异常体系中的异常类型。 5. **资源释放**:无论是否出现异常,最终都会...

    图书管理系统( Spring+Spring MVC+JdbcTemplate).zip

    中央处理单元 (CPU):作为计算机的大脑,负责执行指令、进行逻辑运算和数据处理。 内存:包括随机访问内存 (RAM) 和只读存储器 (ROM),用于临时或永久地存储程序和数据供CPU快速访问。 存储设备:如硬盘、固态...

    SpringiA4_SourceCode:Spring实战第四版源码,学习用。

    3. **跟踪代码流程**:通过创建简单的Spring应用,逐步跟踪代码执行过程,理解依赖注入、AOP等机制的实现。 4. **阅读模块源码**:深入到如Spring MVC、Data Access、WebSocket等具体模块,看它们是如何工作的。 5...

    Spring高级之注解驱动开发视频教程

    n 源码分析-@EnableAspectJAutoproxy注解加载过程分析 n 源码分析-AnnotationAwareAspectJAutoProxyCreator n 技术详解-切入点表达式详解 l Spring JDBC n 基础应用-JdbcTemplate的使用 n 源码分析-自定义...

    spring JDBC

    - **异常转换**:如果执行过程中出现JDBC异常,`JdbcTemplate`会将其转换为Spring定义的异常类型,提高了异常处理的一致性和可读性。 ### 示例代码分析 #### 部分代码实现 下面是一个简单的示例,展示了如何使用...

    spring源码分析免费资源

    Spring AOP是基于代理的,它可以拦截方法调用并在执行前后插入自定义的行为。在源码中,`Advisor`、`Pointcut`和`Aspect`是AOP的核心概念,`ProxyFactoryBean`或`AspectJProxyFactory`用于创建代理对象。理解这些...

    demo-springboot-jdbctemplate:Spring Boot JDBC模板演示

    要使用JdbcTemplate,首先需要在Spring配置类或组件中注入JdbcTemplate实例,然后可以调用其提供的方法执行SQL语句。例如,执行一个查询: ```java @Autowired private JdbcTemplate jdbcTemplate; public ...

    spring源码

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

    spring3.2 编译后源码

    例如,Spring JdbcTemplate 提供了一种声明式的方式来执行数据库操作,降低了对 SQL 的直接依赖。在源码中,可以研究这些模板类的工作机制,以及如何通过回调方法处理结果集。 此外,Spring 3.2 引入了更多对 MVC...

    spring-orm源码

    对于SQL数据库操作,Spring提供了JdbcTemplate和SimpleJdbcTemplate,它们是不依赖于ORM的数据库访问工具。通过源码,我们可以学习到如何编写SQL语句,如何执行查询、更新等操作,以及如何处理结果集。 9. **异常...

    spring技术内幕(第2版)

    视图-控制器(MVC)框架,它提供了一套完整的Web层解决方案,书中将介绍Spring MVC的工作原理,包括DispatcherServlet的工作流程、控制器的处理流程、视图解析过程以及如何配置和使用Spring MVC进行Web开发。...

Global site tag (gtag.js) - Google Analytics