SpringJDBC源码初探-JdbcTemplate类

发布于:2025-07-20 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、JdbcTemplate类介绍

JdbcTemplate 是 Spring JDBC 模块的核心类,它通过模板方法模式封装了传统 JDBC 的复杂操作。主要解决了以下痛点:

资源管理自动化:自动处理连接、语句和结果集的获取与释放
异常统一处理:将受检的 SQLException 转换为 Spring 的运行时异常体系
事务集成:无缝整合 Spring 声明式事务管理

二、 JdbcTemplate核心属性

首先从JdbcTemplate类定义可以看到

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations{
...
}

在这里插入图片描述
JdbcTemplate继承了JdbcAccessor基类并实现了JdbcOperation接口

JdbcAccessor

public abstract class JdbcAccessor implements InitializingBean {

	@Nullable
	private DataSource dataSource;

	@Nullable
	private volatile SQLExceptionTranslator exceptionTranslator;

	private boolean lazyInit = true;
}

可以看到JdbcAccessor 类有两个主要属性dataSource和exceptionTranslator,另外还有一个懒加载标识lazyInit :

  • DataSource 作为所有数据库操作的连接工厂,统一管理数据库连接
  • SQLExceptionTranslator 异常转换器,将底层的 SQLException 转换为 Spring 统一的 DataAccessException 体系
  • lazyInit 延迟初始化标志,控制 exceptionTranslator 的初始化时机:true(默认):首次需要异常转换时才初始化,false:在 JdbcTemplate 初始化时立即创建,避免无数据库操作时的资源浪费

JdbcOperations

JdbcOperations 是 Spring JDBC 模块的核心接口,定义了所有基础的 JDBC 操作抽象

public interface JdbcOperations {
	<T> T execute(ConnectionCallback<T> action) throws DataAccessException;
	<T> T execute(StatementCallback<T> action) throws DataAccessException;
	void execute(String sql) throws DataAccessException;
	<T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException;
	void query(String sql, RowCallbackHandler rch) throws DataAccessException;
	<T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException;
	<T> Stream<T> queryForStream(String sql, RowMapper<T> rowMapper) throws DataAccessException;
	<T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException;
	int update(String sql) throws DataAccessException;
...
}

另外还有一些,配置相关属性

private boolean ignoreWarnings = true;  // 是否忽略SQL警告
private int fetchSize = -1;  // 结果集获取大小
private int maxRows = -1;  // 最大行数限制
private int queryTimeout = -1;  // 查询超时时间(秒)

三、核心方法解析

1.执行方法

1).连接级执行 (ConnectionCallback)

@Override
	@Nullable
	public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");
		// 1. 获取连接
		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		try {
			// Create close-suppressing Connection proxy, also preparing returned Statements.
			Connection conToUse = createConnectionProxy(con);
			// 2. 执行用户回调逻辑
			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.
			String sql = getSql(action);
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			// 3. 异常转换(SQLException -> DataAccessException)
			throw translateException("ConnectionCallback", sql, ex);
		}
		finally {
			// 4. 安全释放连接
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}
  1. 预处理语句执行 (PreparedStatementCallback)
@Nullable
	private <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action, boolean closeResources)
			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 + "]" : ""));
		}
		// 1. 获取连接
		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		PreparedStatement ps = null;
		try {
			// 2. 创建语句
			ps = psc.createPreparedStatement(con);
			applyStatementSettings(ps);
			T result = action.doInPreparedStatement(ps);
			handleWarnings(ps);
			// 3. 执行用户回调
			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 translateException("PreparedStatementCallback", sql, ex);
		}
		finally {
			if (closeResources) {
				if (psc instanceof ParameterDisposer) {
					((ParameterDisposer) psc).cleanupParameters();
				}
				// 4. 关闭语句,释放连接
				JdbcUtils.closeStatement(ps);
				DataSourceUtils.releaseConnection(con, getDataSource());
			}
		}
	}

2.数据查询操作 query方法

@Nullable
	public <T> T query(
			PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
			throws DataAccessException {

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

		return execute(psc, new PreparedStatementCallback<T>() {
			@Override
			@Nullable
			public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
				ResultSet rs = null;
				try {
					// 设置参数
					if (pss != null) {
						pss.setValues(ps);
					}
					// 执行查询
					rs = ps.executeQuery();
					// 处理结果集
					return rse.extractData(rs);
				}
				finally {
					JdbcUtils.closeResultSet(rs);
					if (pss instanceof ParameterDisposer) {
						((ParameterDisposer) pss).cleanupParameters();
					}
				}
			}
		}, true);
	}

另外还有:

public <T> T query(String sql, ResultSetExtractor<T> rse, @Nullable Object... args)
public <T> List<T> query(String sql, RowMapper<T> rowMapper, @Nullable Object... args)
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)
public <T> T queryForObject(String sql, Class<T> requiredType, @Nullable Object... args)
public List<Map<String, Object>> queryForList(String sql, @Nullable Object... args)

这些方法执行查询操作,其中:

  • ResultSetExtractor 用于处理整个ResultSet
  • RowMapper 用于将单行记录映射为对象
  • queryForObject 专用于查询单行记录
  • queryForList() 返回一个List,其中每个元素是一个Map,表示一行记录

3.数据修改操作 (update)

protected int update(final PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss)
			throws DataAccessException {

		logger.debug("Executing prepared SQL update");

		return updateCount(execute(psc, ps -> {
			try {
				if (pss != null) {
					pss.setValues(ps);
				}
				int rows = ps.executeUpdate();
				if (logger.isTraceEnabled()) {
					logger.trace("SQL update affected " + rows + " rows");
				}
				return rows;
			}
			finally {
				if (pss instanceof ParameterDisposer) {
					((ParameterDisposer) pss).cleanupParameters();
				}
			}
		}, true));
	}

update操作主要执行INSERT、UPDATE、DELETE等DML语句,返回受影响的行数,另外还有:

public int update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)// 第二个重载方法可以处理需要获取生成主键的情况
public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss)// batchUpdate主要用来执行批量更新操作

4.存储过程调用

public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)
			throws DataAccessException {

		final List<SqlParameter> updateCountParameters = new ArrayList<>();
		final List<SqlParameter> resultSetParameters = new ArrayList<>();
		final List<SqlParameter> callParameters = new ArrayList<>();

		for (SqlParameter parameter : declaredParameters) {
			if (parameter.isResultsParameter()) {
				if (parameter instanceof SqlReturnResultSet) {
					resultSetParameters.add(parameter);
				}
				else {
					updateCountParameters.add(parameter);
				}
			}
			else {
				callParameters.add(parameter);
			}
		}

		Map<String, Object> result = execute(csc, cs -> {
			boolean retVal = cs.execute();
			int updateCount = cs.getUpdateCount();
			if (logger.isTraceEnabled()) {
				logger.trace("CallableStatement.execute() returned '" + retVal + "'");
				logger.trace("CallableStatement.getUpdateCount() returned " + updateCount);
			}
			Map<String, Object> resultsMap = createResultsMap();
			if (retVal || updateCount != -1) {
				resultsMap.putAll(extractReturnedResults(cs, updateCountParameters, resultSetParameters, updateCount));
			}
			resultsMap.putAll(extractOutputParameters(cs, callParameters));
			return resultsMap;
		});

		Assert.state(result != null, "No result map");
		return result;
	}

用于调用存储过程,支持输入输出参数。

5. 其中涉及到的一些类

  • PreparedStatementCreator用于创建PreparedStatement,允许完全控制PreparedStatement的创建过程。
  • PreparedStatementSetter用于设置PreparedStatement的参数
  • RowMapper将ResultSet中的一行数据映射为一个对象
  • ResultSetExtractor处理整个ResultSet,通常用于复杂的结果集处理。

四、 JdbcTemplate的核心工作流程

  1. 从DataSource获取连接
  2. 创建Statement/PreparedStatement/CallableStatement
  3. 设置参数(如果有)
  4. 执行SQL
  5. 处理结果集(如果是查询)
  6. 处理异常(转换为Spring的DataAccessException)
  7. 清理资源(关闭ResultSet、Statement等)
  8. 返回结果

网站公告

今日签到

点亮在社区的每一天
去签到