JdbcTemplate介绍<二>

引言

如果说JdbcTemplate类是Spring Jdbc的核心类,那么execute方法算得上Spring Jdbc的核心方法了,毕竟JdbcTemplate的很多public方法内部实际上是调用execute方法实现的。

public T execute(ConnectionCallback action) throws DataAccessException

通过使用操作一个JDBC的Connection的回调操作,可以执行JDBC的数据操作,同时支持Spring的事务管理和可以将throw的SQLException转为Spring统一定义的DataAccessException。该回调函数可以返回一个对象,也可以返回结果集。

内部实现

    public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
		Assert.notNull(action,"Callback object must not be null");

		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		try {
			// Create close-suppressing Connection proxy,also preparing returned Statements.
			Connection conToUse = createConnectionProxy(con);
			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.
			DataSourceUtils.releaseConnection(con,getDataSource());
			con = null;
			throw getExceptionTranslator().translate("ConnectionCallback",getSql(action),ex);
		}
		finally {
			DataSourceUtils.releaseConnection(con,getDataSource());
		}
	}

通过查看源代码,我们可以看出ConnectionCallback需要传入一个特殊的Jdbc Connection。

首先DataSourceUtils从当前的数据源获取一个普通Connection(该Connection支持Spring的事务),然后使用createConnectionProxy对这个Connection进行了封装了,使用了JDK动态代理技术,对Connection的一些方法进行了重新处理,比如isClose方法只会返回false,执行close方法时其内部根本就没有关闭。

当抛出SQLException的时候,为了防止初始化异常转换器的时候出现的存放Connecton的池出现死锁,会优先尝试释放该Connection,如果该Connection支持事务则释放,不然则由Spring自行判断是否关闭。实际上通过查看DataSourceUtils的具体实现可以发现,该Connection是通过TransactionSynchronizationManager包装过,因此是支持Spring的事务管理的。

T execute(StatementCallback action) throws DataAccessException

通过使用操作一个JDBC的Statement的回调操作,可以执行JDBC的数据操作,同时支持Spring的事务管理和可以将throw的SQLException转为Spring统一定义的DataAccessException。该回调函数可以返回一个对象,也可以返回结果集。

内部实现

	public <T> T execute(StatementCallback<T> action) throws DataAccessException {
		Assert.notNull(action,"Callback object must not be null");

		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		Statement stmt = null;
		try {
			stmt = con.createStatement();
			applyStatementSettings(stmt);
			T result = action.doInStatement(stmt);
			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",ex);
		}
		finally {
			JdbcUtils.closeStatement(stmt);
			DataSourceUtils.releaseConnection(con,getDataSource());
		}
	}

通过查看源代码,Connection的创建和释放就交给了DataSourceUtils,关于这个类如何创建、释放和关闭Connection,则可以看我的另一篇博客《DataUtils对Connection的获取、释放和关闭的操作学习》。

在获得Connection之后再创建Statement,并且通过applyStatementSettings方法设置Statement的fetchSize、maxRows和timeout属性。在完成了Statement的创建工作之后便是调用StatementCallback回调接口,返回执行结果。不过在返回执行结果之前需要判断是否抛出SQL Warning。如果JdbcTemplate的ignoreWarnings属性为true,即忽略警告,则仅仅在日志做debug处理,否则将会抛出SQLWarningException。

public void execute(final String sql) throws DataAccessException

内部实现

	public void execute(final String sql) throws DataAccessException {
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL statement [" + sql + "]");
		}
		class ExecuteStatementCallback implements StatementCallback<Object>,SqlProvider {
			@Override
			public Object doInStatement(Statement stmt) throws SQLException {
				stmt.execute(sql);
				return null;
			}
			@Override
			public String getSql() {
				return sql;
			}
		}
		execute(new ExecuteStatementCallback());
	}

通过查看源代码,我们可以看出该方法内部实际上通过方法内部类调用了execute(StatementCallback action)方法,因此这也是为什么参数sql为final -- 内部类只能调用外部的final类型变量。

此外,该方法也对sql语句做了日志的debug处理,这样我们可以在调试的时候查看sql语句,前提是我们选择实现的日志框架要支持debug。

public T execute(PreparedStatementCreator psc,PreparedStatementCallback action)

内部实现

	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(obtainDataSource());
		PreparedStatement ps = null;
		try {
			ps = psc.createPreparedStatement(con);
			applyStatementSettings(ps);
			T result = action.doInPreparedStatement(ps);
			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);
			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());
		}
	}

这个execute方法比较少用,主要是通过PreparedStatementCreator来获取PreparedStatement。PreparedStatementCreator接口是JdbcTemplate类使用的两个核心回调接口之一(另外一个是CallableStatementCreator)。此接口通过给定的一个Connection来创建一个PreparedStatement,去负责提供sql语句和任何必要的参数。同时为了更好的方便我们进行debug,建议PreparedStatementCreator实现类也能够继承实现SqlProvider接口。

public T execute(CallableStatementCreator csc,CallableStatementCallback action)

内部实现

	public <T> T execute(CallableStatementCreator csc,CallableStatementCallback<T> action)
			throws DataAccessException {

		Assert.notNull(csc,"CallableStatementCreator must not be null");
		Assert.notNull(action,"Callback object must not be null");
		if (logger.isDebugEnabled()) {
			String sql = getSql(csc);
			logger.debug("Calling stored procedure" + (sql != null ? " [" + sql  + "]" : ""));
		}

		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		CallableStatement cs = null;
		try {
			cs = csc.createCallableStatement(con);
			applyStatementSettings(cs);
			T result = action.doInCallableStatement(cs);
			handleWarnings(cs);
			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 (csc instanceof ParameterDisposer) {
				((ParameterDisposer) csc).cleanupParameters();
			}
			String sql = getSql(csc);
			JdbcUtils.closeStatement(cs);
			cs = null;
			DataSourceUtils.releaseConnection(con,getDataSource());
			con = null;
			throw getExceptionTranslator().translate("CallableStatementCallback",ex);
		}
		finally {
			if (csc instanceof ParameterDisposer) {
				((ParameterDisposer) csc).cleanupParameters();
			}
			JdbcUtils.closeStatement(cs);
			DataSourceUtils.releaseConnection(con,getDataSource());
		}
	}

这个execute方法也比较少用,主要是通过CallableStatementCreator来获取CallableStatement。与PreparedStatementCreator接口类似,CallableStatementCreator是JdbcTemplate接口另外一个的核心回调接口,同样建议也去实现SqlProvider接口。

public T execute(String sql,PreparedStatementCallback action) throws DataAccessException

该方法自定义实现了PreparedStatementCreator接口,调用了execute(PreparedStatementCreator psc,PreparedStatementCallback action)方法。

内部实现

	public <T> T execute(String sql,PreparedStatementCallback<T> action) throws DataAccessException {
		return execute(new SimplePreparedStatementCreator(sql),action);
	}

SimplePreparedStatementCreator的定义

	private static class SimplePreparedStatementCreator implements PreparedStatementCreator,SqlProvider {

		private final String sql;

		public SimplePreparedStatementCreator(String sql) {
			Assert.notNull(sql,"SQL must not be null");
			this.sql = sql;
		}

		@Override
		public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
			return con.prepareStatement(this.sql);
		}

		@Override
		public String getSql() {
			return this.sql;
		}
	}

public T execute(String callString,CallableStatementCallback action) throws DataAccessException

该方法自定义实现了CallableStatementCreator接口,调用了execute(String callString,CallableStatementCallback action)方法。

内部实现

	public <T> T execute(String callString,CallableStatementCallback<T> action) throws DataAccessException {
		return execute(new SimpleCallableStatementCreator(callString),action);
	}

SimpleCallableStatementCreator的定义

	private static class SimpleCallableStatementCreator implements CallableStatementCreator,SqlProvider {

		private final String callString;

		public SimpleCallableStatementCreator(String callString) {
			Assert.notNull(callString,"Call string must not be null");
			this.callString = callString;
		}

		@Override
		public CallableStatement createCallableStatement(Connection con) throws SQLException {
			return con.prepareCall(this.callString);
		}

		@Override
		public String getSql() {
			return this.callString;
		}
	}

相关文章

这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
今天小编给大家分享的是一文解析spring中事务的传播机制,相...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...