Spring源码解读之 JdbcTemplate源码

Spring的JdbcTemplate是Spring框架中用于简化JDBC操作的核心类之一。它通过封装底层的JDBC API,提供了统一、简洁的数据库操作方式,极大地减少了开发人员在数据库操作中需要处理的样板代码,如连接获取、关闭、异常处理等。下面将从源码进行详细解读。

java 复制代码
/*
 * Copyright 2002-present the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.jdbc.core;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.BatchUpdateException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import javax.sql.DataSource;

import org.jspecify.annotations.Nullable;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.InvalidResultSetAccessException;
import org.springframework.jdbc.SQLWarningException;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.jdbc.datasource.ConnectionProxy;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcAccessor;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.StringUtils;

/**
 * <b>JdbcTemplate是Spring JDBC核心包中的委托类。</b>
 * 它提供了一个简化的JDBC操作框架,支持执行各种类型的JDBC操作。
 * 通过这个类,开发者可以避免直接操作JDBC API中的繁琐细节,减少常见错误的发生。对于更简单、更灵活的封装,建议使用{@link org.springframework.jdbc.core.simple.JdbcClient}(自6.1版本起)。
 *
 * <p>JdbcTemplate负责执行JDBC的核心流程:执行SQL语句、处理结果集、处理SQLException,并将其转化为Spring的通用数据访问异常。
 * 该类允许应用程序代码专注于定义SQL和提取结果,JDBC的低级细节(如连接管理、事务处理、异常处理等)由JdbcTemplate自动处理。
 * 
 * <p>开发者使用JdbcTemplate时,只需要提供回调接口(Callback),这些接口为执行具体JDBC操作定义了明确的契约:
 * <ul>
 *   <li>{@link PreparedStatementCreator}用于创建SQL语句及其参数</li>
 *   <li>{@link ResultSetExtractor}用于从ResultSet中提取数据</li>
 *   <li>{@link RowMapper}用于将ResultSet的每一行映射到对象</li>
 * </ul>
 *
 * <p>JdbcTemplate是线程安全的,一旦完成配置,可以在应用中重复使用。它可以直接实例化并提供给服务类,也可以作为Bean配置并通过依赖注入使用。需要注意的是,DataSource应始终在应用程序上下文中配置。
 *
 * <p>此外,JdbcTemplate支持通过自定义SQLExceptionTranslator来翻译数据库异常,避免手动处理SQL错误。
 *
 * <p>所有执行的SQL操作都在DEBUG日志级别记录,以"org.springframework.jdbc.core.JdbcTemplate"作为日志类别。
 * 
 * <p><b>注意:从6.1版本开始,推荐使用{@link org.springframework.jdbc.core.simple.JdbcClient}作为JDBC访问的统一外观,它提供了更灵活、流畅的API风格。</b>
 * {@code JdbcClient}通过委托给JdbcTemplate或NamedParameterJdbcTemplate来执行实际的JDBC操作。
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Thomas Risberg
 * @author Yanming Zhou
 * @since May 3, 2001
 * @see JdbcOperations
 * @see PreparedStatementCreator
 * @see PreparedStatementSetter
 * @see CallableStatementCreator
 * @see PreparedStatementCallback
 * @see CallableStatementCallback
 * @see ResultSetExtractor
 * @see RowCallbackHandler
 * @see RowMapper
 * @see org.springframework.jdbc.support.SQLExceptionTranslator
 * @see org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
 */
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {

	// 结果集的返回前缀标识符
    private static final String RETURN_RESULT_SET_PREFIX = "#result-set-";

    // 更新计数的返回前缀标识符
    private static final String RETURN_UPDATE_COUNT_PREFIX = "#update-count-";

    /** 
     * 指定是否忽略JDBC语句中的SQL警告({@link SQLWarning})。
     * 默认值为{@code true},即忽略并记录警告。如果设置为{@code false},JdbcTemplate将抛出SQL警告异常({@link SQLWarningException})。
     */
    private boolean ignoreWarnings = true;

    /**
     * 设置JDBC查询语句的fetchSize。fetchSize决定一次性从数据库中拉取的记录数,特别适用于处理大规模结果集。
     * 默认值为-1,表示使用JDBC驱动的默认值。如果设置为一个正值,可以通过调整此参数来优化性能。
     */
    private int fetchSize = -1;

    /**
     * 设置JDBC查询语句的最大行数(maxRows)。用于限制查询结果的最大记录数,适用于分页或防止读取过多不需要的数据。
     * 默认值为-1,表示使用JDBC驱动的默认值。
     */
    private int maxRows = -1;

    /**
     * 设置JDBC查询语句的查询超时(单位:秒)。查询超时用于控制查询在执行时的最长时间。
     * 默认值为-1,表示使用JDBC驱动的默认超时设置。
     */
    private int queryTimeout = -1;

    /**
     * 指定是否跳过CallableStatement处理中的结果检查。某些旧版Oracle JDBC驱动(如10.1.0.2)存在处理存储过程返回结果的缺陷,
     * 该选项可以帮助规避此问题。
     */
    private boolean skipResultsProcessing = false;

    /**
     * 如果该值为true,则跳过那些没有相应{@link SqlOutParameter}声明的存储过程返回结果。适用于处理存储过程时,忽略没有定义输出参数的返回结果。
     */
    private boolean skipUndeclaredResults = false;

    /**
     * 如果该值为true,则返回的结果Map会忽略大小写。这对于一些对大小写不敏感的数据库(如Oracle)特别有用。
     */
    private boolean resultsMapCaseInsensitive = false;

    /**
     * 默认构造函数,用于通过Bean配置JdbcTemplate。
     * <p>注意:在使用之前,必须调用{@link #setDataSource}来设置DataSource。
     */
    public JdbcTemplate() {
    }

    /**
     * 构造一个新的JdbcTemplate实例,并通过DataSource获取数据库连接。
     * <p>初始化JdbcTemplate时不会立即触发异常翻译器的初始化。需要手动调用{@link #afterPropertiesSet()}来进行初始化。
     * 
     * @param dataSource 用于获取数据库连接的DataSource
     */
    public JdbcTemplate(DataSource dataSource) {
        setDataSource(dataSource);
        afterPropertiesSet();
    }

    /**
     * 构造一个新的JdbcTemplate实例,并通过DataSource获取数据库连接。
     * <p>根据"lazyInit"标志的设置,是否延迟初始化SQLExceptionTranslator。
     * 
     * @param dataSource 用于获取数据库连接的DataSource
     * @param lazyInit 是否延迟初始化SQLExceptionTranslator
     */
    public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
        setDataSource(dataSource);
        setLazyInit(lazyInit);
        afterPropertiesSet();
    }

    /**
     * 复制构造函数,根据现有的JdbcAccessor实例创建一个新的JdbcTemplate。
     * <p>此构造函数可以用于派生自其他JdbcTemplate实例的子类。
     * 
     * @param original 复制自的原始JdbcTemplate实例
     * @since 7.0
     */
    public JdbcTemplate(JdbcAccessor original) {
        setDataSource(original.getDataSource());
        setExceptionTranslator(original.getExceptionTranslator());
        setLazyInit(original.isLazyInit());
        if (original instanceof JdbcTemplate originalTemplate) {
            setIgnoreWarnings(originalTemplate.isIgnoreWarnings());
            setFetchSize(originalTemplate.getFetchSize());
            setMaxRows(originalTemplate.getMaxRows());
            setQueryTimeout(originalTemplate.getQueryTimeout());
            setSkipResultsProcessing(originalTemplate.isSkipResultsProcessing());
            setSkipUndeclaredResults(originalTemplate.isSkipUndeclaredResults());
            setResultsMapCaseInsensitive(originalTemplate.isResultsMapCaseInsensitive());
        }
    }

    /**
     * 设置是否忽略SQL警告({@link SQLWarning})。如果为false,JdbcTemplate会抛出SQL警告异常。
     * 
     * @param ignoreWarnings 是否忽略SQL警告
     * @see Statement#getWarnings()
     * @see java.sql.SQLWarning
     * @see org.springframework.jdbc.SQLWarningException
     * @see #handleWarnings(Statement)
     */
    public void setIgnoreWarnings(boolean ignoreWarnings) {
        this.ignoreWarnings = ignoreWarnings;
    }

    /**
     * 返回是否忽略SQL警告。
     * 
     * @return true表示忽略警告,false表示不忽略警告
     */
    public boolean isIgnoreWarnings() {
        return this.ignoreWarnings;
    }

    /**
     * 设置JdbcTemplate查询语句的fetchSize。该值控制一次从数据库中检索的记录数量,适用于大数据量的查询。
     * 
     * @param fetchSize 设置的fetchSize值
     * @see java.sql.Statement#setFetchSize
     */
    public void setFetchSize(int fetchSize) {
        this.fetchSize = fetchSize;
    }

    /**
     * 获取当前设置的fetchSize。
     * 
     * @return 当前的fetchSize值
     */
    public int getFetchSize() {
        return this.fetchSize;
    }

    /**
     * 设置JdbcTemplate查询语句的最大行数。对于大数据集的查询,使用此参数可以限制返回的记录数量。
     * 
     * @param maxRows 设置的最大行数
     * @see java.sql.Statement#setMaxRows
     */
    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }


	/**
	 * 返回当前JdbcTemplate实例的最大行数设置。
	 * <p>此设置限制查询结果中最多返回的行数,适用于大数据集或分页查询。若未显式设置,则默认为-1。
	 * 
	 * @return 当前最大行数
	 */
	public int getMaxRows() {
		return this.maxRows;
	}

	/**
	 * 设置JDBC查询的超时时间(单位:秒)。
	 * <p>此设置指定在执行SQL查询时,最多等待多少秒。若设置为-1,则使用JDBC驱动程序的默认超时值。
	 * <p>注意:如果在事务级别设置了超时值,JdbcTemplate的超时设置将被覆盖。
	 * 
	 * @param queryTimeout 超时时间(秒)
	 * @see java.sql.Statement#setQueryTimeout
	 */
	public void setQueryTimeout(int queryTimeout) {
		this.queryTimeout = queryTimeout;
	}

	/**
	 * 返回当前为JdbcTemplate设置的查询超时时间(单位:秒)。
	 * 
	 * @return 当前查询超时时间(秒)
	 */
	public int getQueryTimeout() {
		return this.queryTimeout;
	}

	/**
	 * 设置是否跳过查询结果处理。
	 * <p>此设置适用于CallableStatement,若确定不需要返回任何结果时,跳过结果处理可以优化执行性能。
	 * <p>一些旧版Oracle JDBC驱动(如10.1.0.2)存在处理存储过程返回结果的问题,此设置可以帮助避免这些问题。
	 * 
	 * @param skipResultsProcessing 是否跳过结果处理
	 */
	public void setSkipResultsProcessing(boolean skipResultsProcessing) {
		this.skipResultsProcessing = skipResultsProcessing;
	}

	/**
	 * 返回是否跳过查询结果处理。
	 * 
	 * @return true表示跳过结果处理,false表示不跳过
	 */
	public boolean isSkipResultsProcessing() {
		return this.skipResultsProcessing;
	}

	/**
	 * 设置是否跳过未声明的存储过程结果。
	 * <p>该设置用于在调用存储过程时忽略那些未显式声明的结果。适用于处理没有定义输出参数的存储过程。
	 * 
	 * @param skipUndeclaredResults 是否跳过未声明的存储过程结果
	 */
	public void setSkipUndeclaredResults(boolean skipUndeclaredResults) {
		this.skipUndeclaredResults = skipUndeclaredResults;
	}

	/**
	 * 返回是否跳过未声明的存储过程结果。
	 * 
	 * @return true表示跳过未声明的存储过程结果,false表示不跳过
	 */
	public boolean isSkipUndeclaredResults() {
		return this.skipUndeclaredResults;
	}

	/**
	 * 设置是否对CallableStatement执行结果使用大小写不敏感的Map。
	 * <p>此设置适用于处理那些对参数名大小写不敏感的数据库(如Oracle),在这种情况下,结果Map中的参数名将不区分大小写。
	 * 
	 * @param resultsMapCaseInsensitive 是否使用大小写不敏感的Map
	 */
	public void setResultsMapCaseInsensitive(boolean resultsMapCaseInsensitive) {
		this.resultsMapCaseInsensitive = resultsMapCaseInsensitive;
	}

	/**
	 * 返回是否对CallableStatement执行结果使用大小写不敏感的Map。
	 * 
	 * @return true表示使用大小写不敏感的Map,false表示不使用
	 */
	public boolean isResultsMapCaseInsensitive() {
		return this.resultsMapCaseInsensitive;
	}

	 
	//-------------------------------------------------------------------------
	// Methods dealing with a plain java.sql.Connection
	//-------------------------------------------------------------------------

	/**
	 * 执行一个使用Connection回调的操作。
	 * <p>通过此方法,可以传递一个{@link ConnectionCallback},在获得连接后执行指定操作。
	 * 该方法会自动处理JDBC连接和异常的管理。
	 *
	 * @param action 需要执行的回调操作
	 * @param <T> 回调操作的返回类型
	 * @return 回调执行的结果
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T extends @Nullable Object> T execute(ConnectionCallback<T> action) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");

		// 获取数据库连接并创建代理连接
		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		try {
			// 创建一个Connection代理,处理连接关闭
			Connection conToUse = createConnectionProxy(con);
			return action.doInConnection(conToUse);
		}
		catch (SQLException ex) {
			// 提前释放连接,避免可能的连接池死锁
			String sql = getSql(action);
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw translateException("ConnectionCallback", sql, ex);
		}
		finally {
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

	/**
	 * 创建一个连接的代理对象,代理对象会自动处理连接关闭操作。
	 * <p>该代理还会应用对Statement的设置(如fetchSize、maxRows、queryTimeout等)。
	 * 
	 * @param con 需要代理的JDBC连接
	 * @return 代理的Connection对象
	 * @see java.sql.Connection#close()
	 * @see #execute(ConnectionCallback)
	 * @see #applyStatementSettings
	 */
	protected Connection createConnectionProxy(Connection con) {
		return (Connection) Proxy.newProxyInstance(
				ConnectionProxy.class.getClassLoader(),
				new Class<?>[] {ConnectionProxy.class},
				new CloseSuppressingInvocationHandler(con));
	}


	//-------------------------------------------------------------------------
	// Methods dealing with static SQL (java.sql.Statement)
	//-------------------------------------------------------------------------

	/**
	 * 执行一个Statement回调操作。
	 * <p>通过此方法,可以传递一个{@link StatementCallback},并且自动应用语句设置(如fetchSize、maxRows等)。
	 * 此方法会处理连接和语句的创建、执行和异常管理。
	 *
	 * @param action 执行的回调操作
	 * @param closeResources 是否在操作后关闭资源
	 * @param <T> 回调操作的返回类型
	 * @return 回调执行的结果
	 * @throws DataAccessException 数据访问异常
	 */
	private <T extends @Nullable Object> T execute(StatementCallback<T> action, boolean closeResources) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");

		// 获取数据库连接
		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		Statement stmt = null;
		try {
			// 创建Statement并应用设置
			stmt = con.createStatement();
			applyStatementSettings(stmt);
			T result = action.doInStatement(stmt);
			handleWarnings(stmt);
			return result;
		}
		catch (SQLException ex) {
			// 提前释放连接和语句
			if (stmt != null) {
				handleWarnings(stmt, ex);
			}
			String sql = getSql(action);
			JdbcUtils.closeStatement(stmt);
			stmt = null;
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw translateException("StatementCallback", sql, ex);
		}
		finally {
			if (closeResources) {
				JdbcUtils.closeStatement(stmt);
				DataSourceUtils.releaseConnection(con, getDataSource());
			}
		}
	}

	/**
	 * 执行一个简单的SQL语句(如INSERT、UPDATE等)。
	 * <p>该方法会使用Statement回调来执行SQL语句并进行异常处理。若SQL语句执行时抛出异常,将通过异常翻译进行处理。
	 * 
	 * @param sql 要执行的SQL语句
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075
	public void execute(String sql) throws DataAccessException {
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL statement [" + sql + "]");
		}

		// 定义SQL执行的回调
		class ExecuteStatementCallback implements StatementCallback<@Nullable Object>, SqlProvider {
			@Override
			public @Nullable Object doInStatement(Statement stmt) throws SQLException {
				stmt.execute(sql);
				return null;
			}
			@Override
			public String getSql() {
				return sql;
			}
		}

		execute(new ExecuteStatementCallback(), true);
	}

	/**
	 * 执行一个SQL查询,并通过ResultSetExtractor处理结果。
	 * <p>该方法会执行SQL查询并将查询结果通过传入的ResultSetExtractor转换为目标对象。
	 * 
	 * @param sql SQL查询语句
	 * @param rse 结果集提取器
	 * @param <T> 结果类型
	 * @return 查询结果
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075
	public <T extends @Nullable Object> T query(String sql, 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 + "]");
		}

		// 定义SQL查询的回调
		class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
			@Override
			public @Nullable T doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = null;
				try {
					rs = stmt.executeQuery(sql);
					return rse.extractData(rs);
				}
				finally {
					JdbcUtils.closeResultSet(rs);
				}
			}
			@Override
			public String getSql() {
				return sql;
			}
		}

		return execute(new QueryStatementCallback(), true);
	}

	/**
	 * 执行SQL查询,并使用RowCallbackHandler逐行处理结果。
	 * 
	 * @param sql 查询的SQL语句
	 * @param rch 结果处理器
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075
	public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
		query(sql, new RowCallbackHandlerResultSetExtractor(rch, this.maxRows));
	}

	/**
	 * 执行SQL查询,并将结果映射到指定的对象列表中。
	 * 
	 * @param sql 查询的SQL语句
	 * @param rowMapper 结果行映射器
	 * @param <T> 结果类型
	 * @return 查询结果的对象列表
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T extends @Nullable Object> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
		return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper, 0, this.maxRows)));
	}


	/**
	 * 执行SQL查询并返回一个流(Stream),用于处理大量数据时,可以按需加载每行数据。
	 * <p>该方法使用{@link StatementCallback}执行查询,并将结果集转化为Stream。这样可以实现按需加载结果,适合处理大规模查询结果。
	 * 
	 * @param sql SQL查询语句
	 * @param rowMapper 结果映射器
	 * @param <T> 结果类型
	 * @return 结果流(Stream)
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T> Stream<T> queryForStream(String sql, RowMapper<T> rowMapper) throws DataAccessException {
		class StreamStatementCallback implements StatementCallback<Stream<T>>, SqlProvider {
			@Override
			public Stream<T> doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = stmt.executeQuery(sql);
				Connection con = stmt.getConnection();
				return new ResultSetSpliterator<>(rs, rowMapper, JdbcTemplate.this.maxRows)
						.stream().onClose(() -> {
							JdbcUtils.closeResultSet(rs);
							JdbcUtils.closeStatement(stmt);
							DataSourceUtils.releaseConnection(con, getDataSource());
						});
			}
			@Override
			public String getSql() {
				return sql;
			}
		}

		return result(execute(new StreamStatementCallback(), false));
	}

	/**
	 * 使用查询SQL并将结果映射为一个Map(每列的列名为键,列值为值)。
	 * 
	 * @param sql 查询SQL语句
	 * @return 返回查询结果的Map,键是列名,值是对应列的值
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public Map<String, @Nullable Object> queryForMap(String sql) throws DataAccessException {
		return result(queryForObject(sql, getColumnMapRowMapper()));
	}

	/**
	 * 执行查询,返回一个对象结果。
	 * <p>该方法通过RowMapper将查询结果映射为单个对象。如果查询返回多个结果,方法会抛出异常。
	 * 
	 * @param sql 查询SQL语句
	 * @param rowMapper 结果映射器
	 * @param <T> 结果类型
	 * @return 查询结果的对象
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T extends @Nullable Object> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
		List<T> results = query(sql, rowMapper);
		return DataAccessUtils.nullableSingleResult(results);
	}

	/**
	 * 执行查询,返回一个指定类型的对象。
	 * <p>该方法用于将查询结果映射为单一类型对象,如果查询返回多个结果,会抛出异常。
	 * 
	 * @param sql 查询SQL语句
	 * @param requiredType 结果的类型
	 * @param <T> 结果类型
	 * @return 查询结果的对象
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T> @Nullable T queryForObject(String sql, Class<T> requiredType) throws DataAccessException {
		return queryForObject(sql, getSingleColumnRowMapper(requiredType));
	}

	/**
	 * 执行查询,返回一个对象列表。
	 * <p>该方法将每行的结果映射为指定类型的对象,并返回一个包含所有映射对象的列表。
	 * 
	 * @param sql 查询SQL语句
	 * @param elementType 列表中元素的类型
	 * @param <T> 元素类型
	 * @return 查询结果的对象列表
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075
	public <T> List<@Nullable T> queryForList(String sql, Class<T> elementType) throws DataAccessException {
		return query(sql, getSingleColumnRowMapper(elementType));
	}

	/**
	 * 执行查询,返回一个包含Map的列表,每个Map代表一行数据。
	 * <p>该方法使用列名作为键,将每一行的查询结果映射为一个Map。
	 * 
	 * @param sql 查询SQL语句
	 * @return 查询结果的Map列表
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public List<Map<String, @Nullable Object>> queryForList(String sql) throws DataAccessException {
		return query(sql, getColumnMapRowMapper());
	}

	/**
	 * 执行查询,并返回SqlRowSet。SqlRowSet类似于ResultSet,但它不依赖于数据库连接。
	 * <p>适用于需要批量处理结果的场景。
	 * 
	 * @param sql 查询SQL语句
	 * @return 查询结果的SqlRowSet
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public SqlRowSet queryForRowSet(String sql) throws DataAccessException {
		return result(query(sql, new SqlRowSetResultSetExtractor()));
	}

	/**
	 * 执行SQL更新语句,并返回受影响的行数。
	 * <p>该方法用于执行类似INSERT、UPDATE、DELETE等不返回结果集的SQL语句。
	 * 
	 * @param sql 要执行的SQL更新语句
	 * @return 受影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int update(String sql) throws DataAccessException {
		Assert.notNull(sql, "SQL must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL update [" + sql + "]");
		}

		// 回调执行更新语句
		class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
			@Override
			public Integer doInStatement(Statement stmt) throws SQLException {
				int rows = stmt.executeUpdate(sql);
				if (logger.isTraceEnabled()) {
					logger.trace("SQL update affected " + rows + " rows");
				}
				return rows;
			}
			@Override
			public String getSql() {
				return sql;
			}
		}

		return updateCount(execute(new UpdateStatementCallback(), true));
	}

	/**
	 * 执行批量更新操作,返回每个更新语句的影响行数。
	 * <p>该方法适用于执行多个类似的更新语句(例如批量插入、批量更新等)。
	 * 
	 * @param sql 需要执行的SQL更新语句数组
	 * @return 每个SQL语句影响的行数数组
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int[] batchUpdate(String... sql) throws DataAccessException {
		Assert.notEmpty(sql, "SQL array must not be empty");
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL batch update of " + sql.length + " statements");
		}

		// 执行批量更新
		class BatchUpdateStatementCallback implements StatementCallback<int[]>, SqlProvider {
			private @Nullable String currSql;

			@Override
			public int[] doInStatement(Statement stmt) throws SQLException, DataAccessException {
				int[] rowsAffected = new int[sql.length];
				if (JdbcUtils.supportsBatchUpdates(stmt.getConnection())) {
					for (String sqlStmt : sql) {
						this.currSql = appendSql(this.currSql, sqlStmt);
						stmt.addBatch(sqlStmt);
					}
					try {
						rowsAffected = stmt.executeBatch();
					}
					catch (BatchUpdateException ex) {
						String batchExceptionSql = null;
						for (int i = 0; i < ex.getUpdateCounts().length; i++) {
							if (ex.getUpdateCounts()[i] == Statement.EXECUTE_FAILED) {
								batchExceptionSql = appendSql(batchExceptionSql, sql[i]);
							}
						}
						if (StringUtils.hasLength(batchExceptionSql)) {
							this.currSql = batchExceptionSql;
						}
						throw ex;
					}
				}
				else {
					for (int i = 0; i < sql.length; i++) {
						this.currSql = sql[i];
						if (!stmt.execute(sql[i])) {
							rowsAffected[i] = stmt.getUpdateCount();
						}
						else {
							throw new InvalidDataAccessApiUsageException("Invalid batch SQL statement: " + sql[i]);
						}
					}
				}
				return rowsAffected;
			}

			private String appendSql(@Nullable String sql, String statement) {
				return (StringUtils.hasLength(sql) ? sql + "; " + statement : statement);
			}

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

		int[] result = execute(new BatchUpdateStatementCallback(), true);
		Assert.state(result != null, "No update counts");
		return result;
	}


	/**
	 * 执行SQL查询,返回通过指定参数设置器(PreparedStatementSetter)绑定参数的结果。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param argTypes 参数类型数组
	 * @param rse 结果集提取器
	 * @param <T> 查询结果类型
	 * @return 查询结果
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> T query(String sql, @Nullable Object @Nullable [] args, int[] argTypes, ResultSetExtractor<T> rse) throws DataAccessException {
		return query(sql, newArgTypePreparedStatementSetter(args, argTypes), rse);
	}

	/**
	 * 执行SQL查询,已弃用。使用新的参数绑定机制 `query(String, Object[], int[], ResultSetExtractor)` 替代。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param rse 结果集提取器
	 * @param <T> 查询结果类型
	 * @return 查询结果
	 * @throws DataAccessException 如果查询失败
	 */
	@Deprecated(since = "5.3")
	@Override
	public <T extends @Nullable Object> T query(String sql, @Nullable Object @Nullable [] args, ResultSetExtractor<T> rse) throws DataAccessException {
		return query(sql, newArgPreparedStatementSetter(args), rse);
	}

	/**
	 * 执行SQL查询,返回结果,并使用提供的结果集提取器将结果映射为指定的类型。
	 * @param sql SQL查询语句
	 * @param rse 结果集提取器
	 * @param args 查询参数数组
	 * @param <T> 查询结果类型
	 * @return 查询结果
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> T query(String sql, ResultSetExtractor<T> rse, @Nullable Object @Nullable ... args) throws DataAccessException {
		return query(sql, newArgPreparedStatementSetter(args), rse);
	}

	/**
	 * 执行一个查询,使用提供的 `PreparedStatementCreator` 和 `RowCallbackHandler` 处理结果。
	 * @param psc 生成 `PreparedStatement` 的回调函数
	 * @param rch 处理每行结果的回调函数
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075
	public void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException {
		query(psc, new RowCallbackHandlerResultSetExtractor(rch, this.maxRows));
	}

	/**
	 * 执行查询并处理每行数据,使用 `PreparedStatementSetter` 设置查询参数。
	 * @param sql SQL查询语句
	 * @param pss 查询参数设置器
	 * @param rch 处理每行结果的回调函数
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075
	public void query(String sql, @Nullable PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException {
		query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch, this.maxRows));
	}

	/**
	 * 执行查询,处理每行数据,并使用提供的参数类型设置器。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param argTypes 参数类型数组
	 * @param rch 处理每行结果的回调函数
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public void query(String sql, @Nullable Object @Nullable [] args, int[] argTypes, RowCallbackHandler rch) throws DataAccessException {
		query(sql, newArgTypePreparedStatementSetter(args, argTypes), rch);
	}

	/**
	 * 已弃用的方法,使用新的参数绑定机制。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param rch 处理每行结果的回调函数
	 * @throws DataAccessException 如果查询失败
	 */
	@Deprecated(since = "5.3")
	@Override
	public void query(String sql, @Nullable Object @Nullable [] args, RowCallbackHandler rch) throws DataAccessException {
		query(sql, newArgPreparedStatementSetter(args), rch);
	}

	/**
	 * 执行查询并处理每行结果,使用提供的查询参数。
	 * @param sql SQL查询语句
	 * @param rch 处理每行结果的回调函数
	 * @param args 查询参数数组
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public void query(String sql, RowCallbackHandler rch, @Nullable Object @Nullable ... args) throws DataAccessException {
		query(sql, newArgPreparedStatementSetter(args), rch);
	}

	/**
	 * 执行SQL查询,返回映射为对象列表的结果。使用 `RowMapper` 将每一行结果映射为对象。
	 * @param psc 生成 `PreparedStatement` 的回调函数
	 * @param rowMapper 结果集行映射器
	 * @param <T> 查询结果的类型
	 * @return 查询结果列表
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper) throws DataAccessException {
		return result(query(psc, new RowMapperResultSetExtractor<>(rowMapper, 0, this.maxRows)));
	}

	/**
	 * 执行SQL查询并使用 `RowMapper` 映射每一行结果。
	 * @param sql SQL查询语句
	 * @param pss 查询参数设置器
	 * @param rowMapper 结果集行映射器
	 * @param <T> 查询结果的类型
	 * @return 查询结果列表
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> List<T> query(String sql, @Nullable PreparedStatementSetter pss, RowMapper<T> rowMapper) throws DataAccessException {
		return result(query(sql, pss, new RowMapperResultSetExtractor<>(rowMapper, 0, this.maxRows)));
	}

	/**
	 * 使用给定的 SQL、参数及参数类型,执行查询并返回映射为对象列表的结果。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param argTypes 参数类型数组
	 * @param rowMapper 结果集行映射器
	 * @param <T> 查询结果类型
	 * @return 查询结果列表
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> List<T> query(String sql, @Nullable Object @Nullable [] args, int[] argTypes, RowMapper<T> rowMapper) throws DataAccessException {
		return result(query(sql, args, argTypes, new RowMapperResultSetExtractor<>(rowMapper, 0, this.maxRows)));
	}

	/**
	 * 已弃用的方法,建议使用新的参数绑定机制。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param rowMapper 结果集行映射器
	 * @param <T> 查询结果类型
	 * @return 查询结果列表
	 * @throws DataAccessException 如果查询失败
	 */
	@Deprecated(since = "5.3")
	@Override
	public <T extends @Nullable Object> List<T> query(String sql, @Nullable Object @Nullable [] args, RowMapper<T> rowMapper) throws DataAccessException {
		return result(query(sql, newArgPreparedStatementSetter(args), new RowMapperResultSetExtractor<>(rowMapper, 0, this.maxRows)));
	}

	/**
	 * 使用给定的 SQL 查询并返回映射为对象列表的结果。
	 * @param sql SQL查询语句
	 * @param rowMapper 结果集行映射器
	 * @param args 查询参数数组
	 * @param <T> 查询结果类型
	 * @return 查询结果列表
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> List<T> query(String sql, RowMapper<T> rowMapper, @Nullable Object @Nullable ... args) throws DataAccessException {
		return result(query(sql, newArgPreparedStatementSetter(args), new RowMapperResultSetExtractor<>(rowMapper, 0, this.maxRows)));
	}

	/**
	 * 执行查询并返回一个对象结果,使用 `RowMapper` 映射查询结果。
	 * @param sql SQL查询语句
	 * @param args 查询参数数组
	 * @param argTypes 参数类型数组
	 * @param rowMapper 结果集行映射器
	 * @param <T> 查询结果类型
	 * @return 查询结果对象
	 * @throws DataAccessException 如果查询失败
	 */
	@Override
	public <T extends @Nullable Object> T queryForObject(String sql, @Nullable Object @Nullable [] args, int[] argTypes, RowMapper<T> rowMapper)
			throws DataAccessException {

		List<T> results = query(sql, args, argTypes, new RowMapperResultSetExtractor<>(rowMapper, 1));
		return DataAccessUtils.nullableSingleResult(results);
	}


	// ----------------------------- 查询操作 -----------------------------

	/**
	 * 该方法用于执行 SQL 查询,并将结果映射为单个对象。
	 * 该方法已被弃用,原因是它通过 `RowMapper` 返回结果,而新版本更推荐使用不同的查询模式。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param rowMapper 用于映射查询结果的 RowMapper
	 * @return 返回查询结果的单个对象,若结果为空或不符合条件,则返回 null
	 * @throws DataAccessException 数据访问异常
	 */
	@Deprecated(since = "5.3")
	@Override
	public <T extends @Nullable Object> T queryForObject(String sql, @Nullable Object @Nullable [] args, RowMapper<T> rowMapper) throws DataAccessException {
		// 执行查询,使用 `RowMapperResultSetExtractor` 将结果映射为指定对象
		List<T> results = query(sql, newArgPreparedStatementSetter(args), new RowMapperResultSetExtractor<>(rowMapper, 1));
		// 返回结果的单个对象,若没有符合条件的结果则返回 null
		return DataAccessUtils.nullableSingleResult(results);
	}

	/**
	 * 该方法用于执行 SQL 查询,并将结果映射为单个对象。
	 * 使用了变参 `args` 来传递查询参数。
	 * @param sql 执行的 SQL 查询语句
	 * @param rowMapper 用于映射查询结果的 RowMapper
	 * @param args 查询参数,可以传递多个参数
	 * @return 返回查询结果的单个对象,若结果为空或不符合条件,则返回 null
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T extends @Nullable Object> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object @Nullable ... args) throws DataAccessException {
		// 执行查询,使用 `RowMapperResultSetExtractor` 将结果映射为指定对象
		List<T> results = query(sql, newArgPreparedStatementSetter(args), new RowMapperResultSetExtractor<>(rowMapper, 1));
		// 返回结果的单个对象,若没有符合条件的结果则返回 null
		return DataAccessUtils.nullableSingleResult(results);
	}

	/**
	 * 该方法执行 SQL 查询并返回单个对象。支持通过 `argTypes` 指定参数类型。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param argTypes 参数类型的数组,必须与参数数量一致
	 * @param requiredType 结果对象的类型
	 * @return 返回查询结果的单个对象,若没有符合条件的结果则返回 null
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T> @Nullable T queryForObject(String sql, @Nullable Object @Nullable [] args, int[] argTypes, Class<T> requiredType) throws DataAccessException {
		// 调用其他重载方法来执行查询,并传入 `RowMapper` 处理结果映射
		return queryForObject(sql, args, argTypes, getSingleColumnRowMapper(requiredType));
	}



	/**
	 * 执行 SQL 查询,并将结果映射为单个对象。
	 * 该方法已被弃用,建议使用新的方法实现。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param requiredType 结果对象的类型
	 * @return 查询结果的单个对象,若结果为空或不符合条件则返回 null
	 * @throws DataAccessException 数据访问异常
	 */
	@Deprecated(since = "5.3")
	@Override
	public <T> @Nullable T queryForObject(String sql, @Nullable Object @Nullable [] args, Class<T> requiredType) throws DataAccessException {
		// 调用带 RowMapper 的查询方法,使用 SingleColumnRowMapper 映射结果为指定类型
		return queryForObject(sql, getSingleColumnRowMapper(requiredType), args);
	}

	/**
	 * 执行 SQL 查询,并将结果映射为单个对象。支持通过变参传递查询参数。
	 * @param sql 执行的 SQL 查询语句
	 * @param requiredType 结果对象的类型
	 * @param args 查询参数,可能为 null
	 * @return 查询结果的单个对象,若结果为空或不符合条件则返回 null
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T> @Nullable T queryForObject(String sql, Class<T> requiredType, @Nullable Object @Nullable ... args) throws DataAccessException {
		// 调用带 RowMapper 的查询方法,使用 SingleColumnRowMapper 映射结果为指定类型
		return queryForObject(sql, getSingleColumnRowMapper(requiredType), args);
	}

	/**
	 * 执行 SQL 查询,并返回一个 Map,Map 的键是列名,值是列的值。
	 * 支持通过 `argTypes` 数组指定查询参数类型。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param argTypes 参数类型的数组,必须与查询参数数量一致
	 * @return 返回包含列名和对应值的 Map
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public Map<String, @Nullable Object> queryForMap(String sql, @Nullable Object @Nullable [] args, int[] argTypes) throws DataAccessException {
		// 调用查询方法并返回 Map 结果,使用 ColumnMapRowMapper 将查询结果转换为 Map
		return result(queryForObject(sql, args, argTypes, getColumnMapRowMapper()));
	}

	/**
	 * 执行 SQL 查询,并返回一个 Map,Map 的键是列名,值是列的值。
	 * 该方法使用变参形式接收查询参数。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @return 返回包含列名和对应值的 Map
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public Map<String, @Nullable Object> queryForMap(String sql, @Nullable Object @Nullable ... args) throws DataAccessException {
		// 调用查询方法并返回 Map 结果,使用 ColumnMapRowMapper 将查询结果转换为 Map
		return result(queryForObject(sql, getColumnMapRowMapper(), args));
	}

	/**
	 * 执行 SQL 查询,并返回一个包含查询结果的列表,列表元素为指定类型的对象。
	 * 支持通过 `argTypes` 数组指定查询参数类型。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param argTypes 参数类型的数组,必须与查询参数数量一致
	 * @param elementType 结果列表中每个元素的类型
	 * @return 返回一个包含查询结果的列表,列表中的每个元素是指定类型的对象
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	@SuppressWarnings("NullAway") // Suppress NullAway warnings, which are used for nullability checks
	public <T> List<@Nullable T> queryForList(String sql, @Nullable Object @Nullable [] args, int[] argTypes, Class<T> elementType) throws DataAccessException {
		// 执行查询并将结果映射为指定类型的列表,使用 SingleColumnRowMapper 处理查询结果
		return query(sql, args, argTypes, getSingleColumnRowMapper(elementType));
	}

	/**
	 * 该方法已被弃用,使用新的查询方法。执行 SQL 查询并返回一个包含查询结果的列表。
	 * 结果列表的元素类型由 `elementType` 参数指定。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param elementType 结果列表中每个元素的类型
	 * @return 返回一个包含查询结果的列表,列表中的每个元素是指定类型的对象
	 * @throws DataAccessException 数据访问异常
	 */
	@Deprecated(since = "5.3")
	@Override
	@SuppressWarnings("NullAway")
	public <T> List<@Nullable T> queryForList(String sql, @Nullable Object @Nullable [] args, Class<T> elementType) throws DataAccessException {
		// 调用查询方法并将结果映射为指定类型的列表,使用 SingleColumnRowMapper 处理查询结果
		return query(sql, newArgPreparedStatementSetter(args), getSingleColumnRowMapper(elementType));
	}

	/**
	 * 执行 SQL 查询,并返回一个包含查询结果的列表,列表元素为指定类型的对象。
	 * 该方法使用变参形式接收查询参数。
	 * @param sql 执行的 SQL 查询语句
	 * @param elementType 结果列表中每个元素的类型
	 * @param args 查询参数,可能为 null
	 * @return 返回一个包含查询结果的列表,列表中的每个元素是指定类型的对象
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	@SuppressWarnings("NullAway") // Suppress NullAway warnings, which are used for nullability checks
	public <T> List<@Nullable T> queryForList(String sql, Class<T> elementType, @Nullable Object @Nullable ... args) throws DataAccessException {
		// 执行查询并将结果映射为指定类型的列表,使用 SingleColumnRowMapper 处理查询结果
		return query(sql, newArgPreparedStatementSetter(args), getSingleColumnRowMapper(elementType));
	}

	/**
	 * 执行 SQL 查询,并返回一个包含查询结果的列表,每一项为列名-列值的映射(Map)。
	 * 支持通过 `argTypes` 数组指定查询参数类型。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param argTypes 参数类型的数组,必须与查询参数数量一致
	 * @return 返回一个包含查询结果的列表,每一项为 Map,包含列名和对应的列值
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public List<Map<String, @Nullable Object>> queryForList(String sql, @Nullable Object @Nullable [] args, int[] argTypes) throws DataAccessException {
		// 执行查询并返回包含查询结果的 Map 列表,使用 ColumnMapRowMapper 处理查询结果
		return query(sql, args, argTypes, getColumnMapRowMapper());
	}

	/**
	 * 执行 SQL 查询,并返回一个包含查询结果的列表,每一项为列名-列值的映射(Map)。
	 * 该方法使用变参形式接收查询参数。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @return 返回一个包含查询结果的列表,每一项为 Map,包含列名和对应的列值
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public List<Map<String, @Nullable Object>> queryForList(String sql, @Nullable Object @Nullable ... args) throws DataAccessException {
		// 执行查询并返回包含查询结果的 Map 列表,使用 ColumnMapRowMapper 处理查询结果
		return query(sql, newArgPreparedStatementSetter(args), getColumnMapRowMapper());
	}

	/**
	 * 执行 SQL 查询并返回一个 `SqlRowSet` 对象,表示查询结果集。
	 * 支持通过 `argTypes` 数组指定查询参数类型。
	 * @param sql 执行的 SQL 查询语句
	 * @param args 查询参数,可能为 null
	 * @param argTypes 参数类型的数组,必须与查询参数数量一致
	 * @return 返回查询结果的 `SqlRowSet`,可以进一步操作和遍历
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public SqlRowSet queryForRowSet(String sql, @Nullable Object @Nullable [] args, int[] argTypes) throws DataAccessException {
		// 执行查询并返回一个 `SqlRowSet` 对象,结果集通过 `SqlRowSetResultSetExtractor` 提取
		return result(query(sql, args, argTypes, new SqlRowSetResultSetExtractor()));
	}

	@Override
	public SqlRowSet queryForRowSet(String sql, @Nullable Object @Nullable ... args) throws DataAccessException {
		return result(query(sql, newArgPreparedStatementSetter(args), new SqlRowSetResultSetExtractor()));
	}

	/**
	 * 执行 SQL 更新操作,并根据是否提供 PreparedStatementSetter 来设置参数。
	 *
	 * @param psc  PreparedStatementCreator,用于创建 PreparedStatement
	 * @param pss  PreparedStatementSetter,用于设置 SQL 参数,可为空
	 * @return 更新操作影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	protected int update(PreparedStatementCreator psc, @Nullable PreparedStatementSetter pss)
			throws DataAccessException {

		// 打印调试日志,说明正在执行 SQL 更新操作
		logger.debug("Executing prepared SQL update");

		// 执行更新操作并返回更新的行数
		return updateCount(execute(psc, ps -> {
			try {
				// 如果传入了 PreparedStatementSetter,则设置 SQL 参数
				if (pss != null) {
					pss.setValues(ps);
				}
				// 执行更新,返回受影响的行数
				int rows = ps.executeUpdate();
				
				// 如果日志级别为 TRACE,打印更新受影响的行数
				if (logger.isTraceEnabled()) {
					logger.trace("SQL update affected " + rows + " rows");
				}
				// 返回更新的行数
				return rows;
			}
			finally {
				// 如果 pss 是 ParameterDisposer 的实例,进行清理操作
				if (pss instanceof ParameterDisposer parameterDisposer) {
					parameterDisposer.cleanupParameters();
				}
			}
		}, true));
	}

	/**
	 * 执行 SQL 更新操作,不需要指定 PreparedStatementSetter。
	 *
	 * @param psc  PreparedStatementCreator,用于创建 PreparedStatement
	 * @return 更新操作影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int update(PreparedStatementCreator psc) throws DataAccessException {
		// 无需指定 PreparedStatementSetter,调用上述重载方法
		return update(psc, (PreparedStatementSetter) null);
	}

	/**
	 * 执行 SQL 更新操作,并返回生成的主键。
	 *
	 * @param psc               PreparedStatementCreator,用于创建 PreparedStatement
	 * @param generatedKeyHolder 用于存储生成的主键
	 * @return 更新操作影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)
			throws DataAccessException {

		// 检查 generatedKeyHolder 是否为 null,如果为 null 则抛出异常
		Assert.notNull(generatedKeyHolder, "KeyHolder must not be null");
		logger.debug("Executing SQL update and returning generated keys");

		// 执行更新操作并返回更新的行数
		return updateCount(execute(psc, ps -> {
			// 执行更新操作并返回受影响的行数
			int rows = ps.executeUpdate();
			
			// 清空 KeyHolder 中的键列表
			generatedKeyHolder.getKeyList().clear();
			// 将生成的键存储到 KeyHolder 中
			storeGeneratedKeys(generatedKeyHolder, ps, 1);
			
			// 如果日志级别为 TRACE,打印更新的行数和生成的键数量
			if (logger.isTraceEnabled()) {
				logger.trace("SQL update affected " + rows + " rows and returned " + generatedKeyHolder.getKeyList().size() + " keys");
			}
			// 返回受影响的行数
			return rows;
		}, true));
	}

	/**
	 * 使用 SQL 字符串和 PreparedStatementSetter 执行 SQL 更新操作。
	 *
	 * @param sql  要执行的 SQL 更新语句
	 * @param pss  PreparedStatementSetter,用于设置 SQL 参数,可为空
	 * @return 更新操作影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int update(String sql, @Nullable PreparedStatementSetter pss) throws DataAccessException {
		// 使用 SimplePreparedStatementCreator 创建 PreparedStatement,执行更新操作
		return update(new SimplePreparedStatementCreator(sql), pss);
	}

	/**
	 * 使用 SQL 字符串、参数数组和参数类型数组执行 SQL 更新操作。
	 *
	 * @param sql      要执行的 SQL 更新语句
	 * @param args     参数数组
	 * @param argTypes 参数类型数组
	 * @return 更新操作影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int update(String sql, @Nullable Object @Nullable [] args, int[] argTypes) throws DataAccessException {
		// 根据传入的参数创建 PreparedStatementSetter,然后执行更新操作
		return update(sql, newArgTypePreparedStatementSetter(args, argTypes));
	}

	/**
	 * 使用 SQL 字符串和参数数组执行 SQL 更新操作。
	 *
	 * @param sql  要执行的 SQL 更新语句
	 * @param args 参数数组
	 * @return 更新操作影响的行数
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int update(String sql, @Nullable Object @Nullable ... args) throws DataAccessException {
		// 根据传入的参数创建 PreparedStatementSetter,然后执行更新操作
		return update(sql, newArgPreparedStatementSetter(args));
	}

	/**
	 * 执行批量更新操作,并返回每个更新操作的影响结果。
	 *
	 * @param psc               PreparedStatementCreator,用于创建 PreparedStatement
	 * @param pss               BatchPreparedStatementSetter,用于批量设置 SQL 参数
	 * @param generatedKeyHolder 用于存储生成的主键
	 * @return 每个更新操作影响的行数数组
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int[] batchUpdate(PreparedStatementCreator psc, BatchPreparedStatementSetter pss,
			KeyHolder generatedKeyHolder) throws DataAccessException {

		// 执行批量更新操作,返回更新结果
		int[] result = execute(psc, getPreparedStatementCallback(pss, generatedKeyHolder));

		// 确保返回的结果数组不为空
		Assert.state(result != null, "No result array");
		// 返回更新结果
		return result;
	}


	/**
	 * 执行 SQL 批量更新操作。
	 * 
	 * @param sql SQL 更新语句
	 * @param pss BatchPreparedStatementSetter 用于设置每个批次的 SQL 参数
	 * @return 每个批次操作的影响行数数组
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int[] batchUpdate(String sql, BatchPreparedStatementSetter pss) throws DataAccessException {
		// 如果调试级别日志开启,打印正在执行的 SQL 批量更新语句
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL batch update [" + sql + "]");
		}
		
		// 获取批次大小
		int batchSize = pss.getBatchSize();
		
		// 如果批次大小为 0,直接返回空数组
		if (batchSize == 0) {
			return new int[0];
		}

		// 执行批量更新操作,返回每个批次的影响行数数组
		int[] result = execute(sql, getPreparedStatementCallback(pss, null));
		
		// 确保返回的结果数组不为空
		Assert.state(result != null, "No result array");
		
		// 返回批量更新操作的影响行数数组
		return result;
	}

	/**
	 * 使用给定的 SQL 和参数列表执行 SQL 批量更新操作。
	 * 
	 * @param sql SQL 更新语句
	 * @param batchArgs 每个批次的参数列表
	 * @return 每个批次操作的影响行数数组
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int[] batchUpdate(String sql, List<Object[]> batchArgs) throws DataAccessException {
		// 调用重载方法 batchUpdate,并提供一个空的 argTypes 数组
		return batchUpdate(sql, batchArgs, new int[0]);
	}

	/**
	 * 使用给定的 SQL 和参数列表执行 SQL 批量更新操作,并且指定参数类型。
	 * 
	 * @param sql SQL 更新语句
	 * @param batchArgs 每个批次的参数列表
	 * @param argTypes 参数类型数组
	 * @return 每个批次操作的影响行数数组
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes) throws DataAccessException {
		// 如果批次参数列表为空,直接返回空数组
		if (batchArgs.isEmpty()) {
			return new int[0];
		}

		// 调用 batchUpdate 方法,构造一个新的 BatchPreparedStatementSetter
		return batchUpdate(
				sql,
				new BatchPreparedStatementSetter() {
					@Override
					public void setValues(PreparedStatement ps, int i) throws SQLException {
						// 获取当前批次的参数值
						Object[] values = batchArgs.get(i);
						int colIndex = 0;
						
						// 为每列参数设置值
						for (Object value : values) {
							colIndex++;
							
							// 如果值是 SqlParameterValue 类型,则使用 StatementCreatorUtils 设置
							if (value instanceof SqlParameterValue paramValue) {
								StatementCreatorUtils.setParameterValue(ps, colIndex, paramValue, paramValue.getValue());
							}
							else {
								int colType;
								
								// 如果没有足够的参数类型,默认使用 TYPE_UNKNOWN
								if (argTypes.length < colIndex) {
									colType = SqlTypeValue.TYPE_UNKNOWN;
								}
								else {
									colType = argTypes[colIndex - 1];
								}
								
								// 使用 StatementCreatorUtils 设置参数
								StatementCreatorUtils.setParameterValue(ps, colIndex, colType, value);
							}
						}
					}
					
					@Override
					public int getBatchSize() {
						// 返回批次的大小(即参数列表的长度)
						return batchArgs.size();
					}
				});
	}

	/**
	 * 执行 SQL 批量更新操作。
	 * 
	 * @param sql SQL 更新语句
	 * @param batchArgs 批量参数集合
	 * @param batchSize 每批次的大小
	 * @param pss 用于设置 SQL 参数的回调接口
	 * @param <T> 参数类型
	 * @return 每批次更新的影响行数数组
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T> int[][] batchUpdate(String sql, Collection<T> batchArgs, int batchSize,
			ParameterizedPreparedStatementSetter<T> pss) throws DataAccessException {

		// 如果开启了调试日志,打印 SQL 批量更新的信息
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL batch update [" + sql + "] with a batch size of " + batchSize);
		}
		
		// 执行 SQL 批量更新操作
		int[][] result = execute(sql, (PreparedStatementCallback<int[][]>) ps -> {
			List<int[]> rowsAffected = new ArrayList<>();
			try {
				// 检查当前数据库连接是否支持批量更新
				boolean batchSupported = JdbcUtils.supportsBatchUpdates(ps.getConnection());
				int n = 0;
				
				// 遍历每个批量参数对象
				for (T obj : batchArgs) {
					pss.setValues(ps, obj); // 设置 SQL 参数
					n++; // 批次计数
					
					if (batchSupported) {
						// 如果支持批量更新,添加到批次中
						ps.addBatch();
						
						// 当批次达到指定大小或是最后一个参数时,执行批量更新
						if (n % batchSize == 0 || n == batchArgs.size()) {
							if (logger.isTraceEnabled()) {
								// 打印批次信息
								int batchIdx = (n % batchSize == 0) ? n / batchSize : (n / batchSize) + 1;
								int items = n - ((n % batchSize == 0) ? n / batchSize - 1 : (n / batchSize)) * batchSize;
								logger.trace("Sending SQL batch update #" + batchIdx + " with " + items + " items");
							}
							
							try {
								// 执行批量更新
								int[] updateCounts = ps.executeBatch();
								rowsAffected.add(updateCounts);
							}
							catch (BatchUpdateException ex) {
								// 如果发生批量更新异常,抛出合并异常
								throw new AggregatedBatchUpdateException(rowsAffected.toArray(int[][]::new), ex);
							}
						}
					}
					else {
						// 如果不支持批量更新,则逐个执行更新操作
						int i = ps.executeUpdate();
						rowsAffected.add(new int[] {i});
					}
				}
				
				// 将所有批量操作的更新结果转成二维数组返回
				int[][] result1 = new int[rowsAffected.size()][]; 
				for (int i = 0; i < result1.length; i++) {
					result1[i] = rowsAffected.get(i);
				}
				return result1;
			}
			finally {
				// 如果参数设置器实现了 ParameterDisposer,进行参数清理
				if (pss instanceof ParameterDisposer parameterDisposer) {
					parameterDisposer.cleanupParameters();
				}
			}
		});

		// 确保返回的结果不为空
		Assert.state(result != null, "No result array");
		return result;
	}

	//------------------------------------------------------------------------- 
	// 处理可调用语句的方法
	//-------------------------------------------------------------------------

	/**
	 * 执行存储过程,提供 CallableStatementCallback 操作。
	 * 
	 * @param csc CallableStatementCreator,用于创建 CallableStatement
	 * @param action 存储过程的回调接口
	 * @param <T> 存储过程返回值类型
	 * @return 存储过程执行的返回值
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T extends @Nullable Object> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action)
			throws DataAccessException {

		// 确保传入的参数不为 null
		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 + "]" : ""));
		}

		// 获取数据库连接并创建 CallableStatement
		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) {
			// 捕获 SQLException 异常并处理
			if (csc instanceof ParameterDisposer parameterDisposer) {
				parameterDisposer.cleanupParameters(); // 清理参数
			}
			if (cs != null) {
				handleWarnings(cs, ex); // 处理警告
			}
			String sql = getSql(csc);
			csc = null;
			JdbcUtils.closeStatement(cs); // 关闭 Statement
			cs = null;
			DataSourceUtils.releaseConnection(con, getDataSource()); // 释放连接
			con = null;
			// 转换并抛出异常
			throw translateException("CallableStatementCallback", sql, ex);
		}
		finally {
			// 在 finally 中确保参数和连接被清理
			if (csc instanceof ParameterDisposer parameterDisposer) {
				parameterDisposer.cleanupParameters();
			}
			JdbcUtils.closeStatement(cs);
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

	/**
	 * 执行存储过程,提供调用字符串和 CallableStatementCallback 操作。
	 * 
	 * @param callString 存储过程的调用字符串
	 * @param action 存储过程回调接口
	 * @param <T> 存储过程返回值类型
	 * @return 存储过程执行的返回值
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public <T extends @Nullable Object> T execute(String callString, CallableStatementCallback<T> action) throws DataAccessException {
		// 使用 SimpleCallableStatementCreator 创建 CallableStatement,并执行回调
		return execute(new SimpleCallableStatementCreator(callString), action);
	}

	/**
	 * 调用存储过程并提取输出参数和结果集。
	 * 
	 * @param csc CallableStatementCreator,用于创建 CallableStatement
	 * @param declaredParameters 存储过程声明的参数
	 * @return 存储过程返回的结果 Map
	 * @throws DataAccessException 数据访问异常
	 */
	@Override
	public Map<String, @Nullable Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)
			throws DataAccessException {

		List<SqlParameter> updateCountParameters = new ArrayList<>();
		List<SqlParameter> resultSetParameters = new ArrayList<>();
		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, @Nullable 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
			Map<String, @Nullable 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;
	}

	/**
	 * 从存储过程的 CallableStatement 中提取返回的结果集。
	 * 
	 * @param cs 存储过程的 CallableStatement
	 * @param updateCountParameters 更新计数参数
	 * @param resultSetParameters 结果集参数
	 * @param updateCount 更新计数
	 * @return 返回的结果 Map
	 * @throws SQLException SQL 异常
	 */
	protected Map<String, @Nullable Object> extractReturnedResults(CallableStatement cs,
			@Nullable List<SqlParameter> updateCountParameters, @Nullable List<SqlParameter> resultSetParameters,
			int updateCount) throws SQLException {

		// 结果集存储 Map
		Map<String, @Nullable Object> results = new LinkedHashMap<>(4);
		int rsIndex = 0;
		int updateIndex = 0;
		boolean moreResults;
		
		// 如果没有跳过结果处理,则提取结果
		if (!isSkipResultsProcessing()) {
			do {
				// 处理结果集或更新计数
				if (updateCount == -1) {
					// 处理结果集
					if (resultSetParameters != null && resultSetParameters.size() > rsIndex) {
						SqlReturnResultSet declaredRsParam = (SqlReturnResultSet) resultSetParameters.get(rsIndex);
						results.putAll(processResultSet(cs.getResultSet(), declaredRsParam));
						rsIndex++;
					}
					else {
						// 如果没有声明的结果集参数,使用默认参数
						if (!isSkipUndeclaredResults()) {
							String rsName = RETURN_RESULT_SET_PREFIX + (rsIndex + 1);
							SqlReturnResultSet undeclaredRsParam = new SqlReturnResultSet(rsName, getColumnMapRowMapper());
							if (logger.isTraceEnabled()) {
								logger.trace("Added default SqlReturnResultSet parameter named '" + rsName + "'");
							}
							results.putAll(processResultSet(cs.getResultSet(), undeclaredRsParam));
							rsIndex++;
						}
					}
				}
				else {
					// 处理更新计数
					if (updateCountParameters != null && updateCountParameters.size() > updateIndex) {
						SqlReturnUpdateCount ucParam = (SqlReturnUpdateCount) updateCountParameters.get(updateIndex);
						String declaredUcName = ucParam.getName();
						results.put(declaredUcName, updateCount);
						updateIndex++;
					}
					else {
						// 如果没有声明的更新计数参数,使用默认参数
						if (!isSkipUndeclaredResults()) {
							String undeclaredName = RETURN_UPDATE_COUNT_PREFIX + (updateIndex + 1);
							if (logger.isTraceEnabled()) {
								logger.trace("Added default SqlReturnUpdateCount parameter named '" + undeclaredName + "'");
							}
							results.put(undeclaredName, updateCount);
							updateIndex++;
						}
					}
				}
				
				// 获取是否有更多结果
				moreResults = cs.getMoreResults();
				updateCount = cs.getUpdateCount();
				if (logger.isTraceEnabled()) {
					logger.trace("CallableStatement.getUpdateCount() returned " + updateCount);
				}
			}
			while (moreResults || updateCount != -1);
		}
		return results;
	}

	/**
	 * 从已完成的存储过程中提取输出参数。
	 * 
	 * @param cs 存储过程的 JDBC 包装器
	 * @param parameters 存储过程的参数列表
	 * @return 包含返回结果的 Map
	 * @throws SQLException SQL 异常
	 */
	protected Map<String, @Nullable Object> extractOutputParameters(CallableStatement cs, List<SqlParameter> parameters)
			throws SQLException {

		Map<String, @Nullable Object> results = CollectionUtils.newLinkedHashMap(parameters.size());
		int sqlColIndex = 1;
		for (SqlParameter param : parameters) {
			if (param instanceof SqlOutParameter outParam) {
				Assert.state(outParam.getName() != null, "Anonymous parameters not allowed");
				SqlReturnType returnType = outParam.getSqlReturnType();
				// 如果返回类型不为空,则使用该类型获取参数值
				if (returnType != null) {
					Object out = returnType.getTypeValue(cs, sqlColIndex, outParam.getSqlType(), outParam.getTypeName());
					results.put(outParam.getName(), out);
				}
				else {
					// 如果返回类型为空,则直接获取对象值
					Object out = cs.getObject(sqlColIndex);
					// 如果返回值是 ResultSet 类型,则根据参数配置处理该结果集
					if (out instanceof ResultSet resultSet) {
						if (outParam.isResultSetSupported()) {
							results.putAll(processResultSet(resultSet, outParam));
						}
						else {
							String rsName = outParam.getName();
							SqlReturnResultSet rsParam = new SqlReturnResultSet(rsName, getColumnMapRowMapper());
							results.putAll(processResultSet(resultSet, rsParam));
							 // 如果开启了日志,记录添加的默认参数名
							if (logger.isTraceEnabled()) {
								logger.trace("Added default SqlReturnResultSet parameter named '" + rsName + "'");
							}
						}
					}
					else {
						results.put(outParam.getName(), out);
					}
				}
			}
			 // 如果当前参数不是结果参数,继续下一个参数的处理
			if (!param.isResultsParameter()) {
				sqlColIndex++;
			}
		}
		return results;
	}

	/**
	 * 处理存储过程返回的 ResultSet。
	 * 
	 * @param rs 存储过程返回的 ResultSet
	 * @param param 对应的存储过程参数
	 * @return 包含返回结果的 Map
	 * @throws SQLException SQL 异常
	 */
	@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/950
	protected Map<@Nullable String, @Nullable Object> processResultSet(
			@Nullable ResultSet rs, ResultSetSupportingSqlParameter param) throws SQLException {

		if (rs != null) {
			try {
				// 根据参数配置,使用不同的方式处理 ResultSet
				if (param.getRowMapper() != null) {
					RowMapper<? extends @Nullable Object> rowMapper = param.getRowMapper();
					Object data = (new RowMapperResultSetExtractor<>(rowMapper)).extractData(rs);
					return Collections.singletonMap(param.getName(), data);
				}
				else if (param.getRowCallbackHandler() != null) {
					RowCallbackHandler rch = param.getRowCallbackHandler();
					(new RowCallbackHandlerResultSetExtractor(rch, -1)).extractData(rs);
					return Collections.singletonMap(param.getName(),
							"ResultSet returned from stored procedure was processed");
				}
				else if (param.getResultSetExtractor() != null) {
					Object data = param.getResultSetExtractor().extractData(rs);
					return Collections.singletonMap(param.getName(), data);
				}
			}
			finally {
				// 确保关闭 ResultSet
				JdbcUtils.closeResultSet(rs);
			}
		}
		return Collections.emptyMap();
	}


	//-------------------------------------------------------------------------
	// Implementation hooks and helper methods
	//-------------------------------------------------------------------------

	/**
	 * 创建一个新的 RowMapper,用于将列读取为键值对。
	 * 
	 * @return 用于映射的 RowMapper
	 * @see ColumnMapRowMapper
	 */
	protected RowMapper<Map<String, @Nullable Object>> getColumnMapRowMapper() {
		return new ColumnMapRowMapper();
	}

	/**
	 * 创建一个新的 RowMapper,用于从单列中读取结果对象。
	 * 
	 * @param requiredType 每个结果对象需要匹配的类型
	 * @return 用于映射的 RowMapper
	 * @see SingleColumnRowMapper
	 */
	protected <T> RowMapper<@Nullable T> getSingleColumnRowMapper(Class<T> requiredType) {
		return new SingleColumnRowMapper<>(requiredType);
	}

	/**
	 * 创建一个 Map 实例,用作结果的存储 Map。
	 * 
	 * <p>如果 {@link #resultsMapCaseInsensitive} 设置为 true,
	 * 则创建一个 {@link LinkedCaseInsensitiveMap};否则,创建一个
	 * {@link LinkedHashMap}。
	 * 
	 * @return 结果 Map 实例
	 * @see #setResultsMapCaseInsensitive
	 * @see #isResultsMapCaseInsensitive
	 */
	protected Map<String, @Nullable Object> createResultsMap() {
		// 如果启用了大小写不敏感的结果 Map,则创建一个 LinkedCaseInsensitiveMap
		if (isResultsMapCaseInsensitive()) {
			return new LinkedCaseInsensitiveMap<>();
		}
		else {
			// 否则,创建一个默认的 LinkedHashMap
			return new LinkedHashMap<>();
		}
	}

	/**
	 * 准备给定的 JDBC Statement(或 PreparedStatement 或 CallableStatement),
	 * 应用语句设置,如 fetch size、最大行数和查询超时。
	 * 
	 * @param stmt 要准备的 JDBC Statement
	 * @throws SQLException 如果 JDBC API 抛出异常
	 * @see #setFetchSize
	 * @see #setMaxRows
	 * @see #setQueryTimeout
	 * @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
	 */
	protected void applyStatementSettings(Statement stmt) throws SQLException {
		// 获取设置的 fetchSize,如果不为 -1,则应用到 Statement
		int fetchSize = getFetchSize();
		if (fetchSize != -1) {
			stmt.setFetchSize(fetchSize);
		}

		// 获取设置的 maxRows,如果不为 -1,则应用到 Statement
		int maxRows = getMaxRows();
		if (maxRows != -1) {
			stmt.setMaxRows(maxRows);
		}

		// 应用查询超时设置
		DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());
	}

	/**
	 * 根据传入的参数创建一个新的基于参数的 PreparedStatementSetter。
	 * 
	 * <p>默认情况下,会创建一个 {@link ArgumentPreparedStatementSetter}。
	 * 该方法允许子类重写自定义创建过程。
	 * 
	 * @param args 参数数组
	 * @return 新的 PreparedStatementSetter
	 */
	protected PreparedStatementSetter newArgPreparedStatementSetter(@Nullable Object @Nullable [] args) {
		// 创建一个新的 ArgumentPreparedStatementSetter 并返回
		return new ArgumentPreparedStatementSetter(args);
	}

	/**
	 * 根据传入的参数和类型创建一个新的基于参数类型的 PreparedStatementSetter。
	 * 
	 * <p>默认情况下,会创建一个 {@link ArgumentTypePreparedStatementSetter}。
	 * 该方法允许子类重写自定义创建过程。
	 * 
	 * @param args 参数数组
	 * @param argTypes 与参数对应的 SQL 类型数组
	 * @return 新的 PreparedStatementSetter
	 */
	protected PreparedStatementSetter newArgTypePreparedStatementSetter(@Nullable Object @Nullable [] args, int[] argTypes) {
		// 创建一个新的 ArgumentTypePreparedStatementSetter 并返回
		return new ArgumentTypePreparedStatementSetter(args, argTypes);
	}

	/**
	 * 在传播执行语句时的主要 {@code SQLException} 之前处理警告信息。
	 * 
	 * <p>会调用常规的 {@link #handleWarnings(Statement)} 方法,但捕获
	 * {@link SQLWarningException},以便将 {@link SQLWarning} 链接到主要异常。
	 * 
	 * @param stmt 当前的 JDBC Statement
	 * @param ex 执行语句失败后的主要异常
	 * @since 5.3.29
	 * @see #handleWarnings(Statement)
	 * @see SQLException#setNextException
	 */
	protected void handleWarnings(Statement stmt, SQLException ex) {
		try {
			handleWarnings(stmt);
		}
		catch (SQLWarningException nonIgnoredWarning) {
			ex.setNextException(nonIgnoredWarning.getSQLWarning());
		}
		catch (SQLException warningsEx) {
			logger.debug("Failed to retrieve warnings", warningsEx);
		}
		catch (Throwable warningsEx) {
			logger.debug("Failed to process warnings", warningsEx);
		}
	}

	/**
	 * 处理给定 JDBC 语句的警告(如果有的话)。
	 * 
	 * <p>如果没有忽略警告,则抛出 {@link SQLWarningException},
	 * 否则以调试级别记录警告信息。
	 * 
	 * @param stmt 当前的 JDBC 语句
	 * @throws SQLException 如果获取警告时失败
	 * @throws SQLWarningException 如果遇到警告且不忽略该警告时,抛出该异常
	 * @see #setIgnoreWarnings
	 * @see #handleWarnings(SQLWarning)
	 */
	protected void handleWarnings(Statement stmt) throws SQLException, SQLWarningException {
		 // 如果忽略警告
		if (isIgnoreWarnings()) {
			// 如果日志级别为调试,则记录警告信息
			if (logger.isDebugEnabled()) {
				SQLWarning warningToLog = stmt.getWarnings();
				while (warningToLog != null) {
					logger.debug("SQLWarning ignored: SQL state '" + warningToLog.getSQLState() + "', error code '" +
							warningToLog.getErrorCode() + "', message [" + warningToLog.getMessage() + "]");
					warningToLog = warningToLog.getNextWarning();
				}
			}
		}
		else {
			// 如果没有忽略警告,调用处理警告的方法
			handleWarnings(stmt.getWarnings());
		}
	}

	/**
	 * 如果遇到实际的警告,则抛出 {@link SQLWarningException}。
	 * 
	 * @param warning 当前语句的警告对象,可能为 {@code null},如果是 {@code null},则什么都不做
	 * @throws SQLWarningException 如果遇到实际警告时抛出
	 */
	protected void handleWarnings(@Nullable SQLWarning warning) throws SQLWarningException {
		if (warning != null) {
			throw new SQLWarningException("Warning not ignored", warning);
		}
	}

	/**
	 * 将给定的 {@link SQLException} 转换为通用的 {@link DataAccessException}。
	 * 
	 * @param task 描述当前尝试执行的任务的可读文本
	 * @param sql 发生问题的 SQL 查询或更新(可能为 {@code null})
	 * @param ex 触发问题的 {@code SQLException}
	 * @return 一个封装了 {@code SQLException} 的 DataAccessException(永远不为 {@code null})
	 * @since 5.0
	 * @see #getExceptionTranslator()
	 */
	protected DataAccessException translateException(String task, @Nullable String sql, SQLException ex) {
		DataAccessException dae = getExceptionTranslator().translate(task, sql, ex);
		return (dae != null ? dae : new UncategorizedSQLException(task, sql, ex));
	}


	/**
	 * 从潜在的提供者对象中获取 SQL 查询。
	 * 
	 * @param obj 可能是 SqlProvider 类型的对象
	 * @return SQL 字符串,如果未知则返回 {@code null}
	 * @see SqlProvider
	 */
	private static @Nullable String getSql(Object obj) {
		return (obj instanceof SqlProvider sqlProvider ? sqlProvider.getSql() : null);
	}

	/**
	 * 断言返回结果不为 null,如果为 null 会抛出异常。
	 * 
	 * @param result 返回的结果
	 * @return 非 null 的结果
	 * @throws IllegalStateException 如果结果为 null
	 */
	private static <T> T result(@Nullable T result) {
		Assert.state(result != null, "No result");
		return result;
	}

	/**
	 * 断言更新计数不为 null,如果为 null 会抛出异常。
	 * 
	 * @param result 返回的更新计数
	 * @return 非 null 的更新计数
	 * @throws IllegalStateException 如果更新计数为 null
	 */
	private static int updateCount(@Nullable Integer result) {
		Assert.state(result != null, "No update count");
		return result;
	}

	/**
	 * 存储生成的键到 KeyHolder。
	 * 
	 * @param generatedKeyHolder 存储生成的键的 KeyHolder
	 * @param ps 执行插入操作的 PreparedStatement
	 * @param rowsExpected 期望的行数
	 * @throws SQLException 如果获取生成的键时失败
	 */
	private void storeGeneratedKeys(KeyHolder generatedKeyHolder, PreparedStatement ps, int rowsExpected)
			throws SQLException {

		// 获取生成的键并将其存储到 KeyHolder 中
		List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
		ResultSet keys = ps.getGeneratedKeys();
		if (keys != null) {
			try {
				// 使用 RowMapper 解析生成的键并添加到生成的键列表中
				RowMapperResultSetExtractor<Map<String, Object>> rse =
						new RowMapperResultSetExtractor<>(getColumnMapRowMapper(), rowsExpected);
				generatedKeys.addAll(result(rse.extractData(keys)));
			}
			finally {
				JdbcUtils.closeResultSet(keys);
			}
		}
	}

	/**
	 * 创建一个 PreparedStatementCallback 用于批量操作。
	 * 
	 * @param pss 批量操作的 PreparedStatementSetter
	 * @param generatedKeyHolder 存储生成键的 KeyHolder(可选)
	 * @return PreparedStatementCallback
	 */
	private PreparedStatementCallback<int[]> getPreparedStatementCallback(BatchPreparedStatementSetter pss,
			@Nullable KeyHolder generatedKeyHolder) {
		return ps -> {
			try {
				 // 获取批量操作的大小
				int batchSize = pss.getBatchSize();
				// 如果是可中断的批量操作,获取其特定实现
				InterruptibleBatchPreparedStatementSetter ipss =
						(pss instanceof InterruptibleBatchPreparedStatementSetter ibpss ? ibpss : null);
				// 如果提供了 KeyHolder,清空它
				if (generatedKeyHolder != null) {
					generatedKeyHolder.getKeyList().clear();
				}
				// 检查数据库是否支持批量更新
				if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
					for (int i = 0; i < batchSize; i++) {
						// 执行批量更新操作
						pss.setValues(ps, i);
						if (ipss != null && ipss.isBatchExhausted(i)) {
							break;
						}
						ps.addBatch();
					}
					int[] results = ps.executeBatch();
					// 如果提供了 KeyHolder,存储生成的键
					if (generatedKeyHolder != null) {
						storeGeneratedKeys(generatedKeyHolder, ps, batchSize);
					}
					return results;
				}
				else {
					 // 如果不支持批量更新,逐个执行更新操作
					List<Integer> rowsAffected = new ArrayList<>();
					for (int i = 0; i < batchSize; i++) {
						pss.setValues(ps, i);
						if (ipss != null && ipss.isBatchExhausted(i)) {
							break;
						}
						rowsAffected.add(ps.executeUpdate());
						// 如果提供了 KeyHolder,存储生成的键
						if (generatedKeyHolder != null) {
							storeGeneratedKeys(generatedKeyHolder, ps, 1);
						}
					}
					// 转换结果为数组并返回
					int[] rowsAffectedArray = new int[rowsAffected.size()];
					for (int i = 0; i < rowsAffectedArray.length; i++) {
						rowsAffectedArray[i] = rowsAffected.get(i);
					}
					return rowsAffectedArray;
				}
			}
			finally {
				if (pss instanceof ParameterDisposer parameterDisposer) {
					parameterDisposer.cleanupParameters();
				}
			}
		};
	}


	/**
	 * 一个调用处理器,用于抑制对 JDBC 连接的关闭调用。
	 * 还会准备返回的 Statement(Prepared/CallbackStatement)对象。
	 * @see java.sql.Connection#close()
	 */
	private class CloseSuppressingInvocationHandler implements InvocationHandler {

		private final Connection target;

		public CloseSuppressingInvocationHandler(Connection target) {
			this.target = target;
		}

		@Override
		public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			// 对 ConnectionProxy 接口的调用...

			return switch (method.getName()) {
				// 只有代理对象相同才认为是 equals
				case "equals" -> (proxy == args[0]);
				// 使用 Connection 代理的 hashCode
				case "hashCode" -> System.identityHashCode(proxy);
				// 处理 close 方法:抑制,不能执行关闭操作
				case "close" -> null;
				case "isClosed" -> false;
				// 处理 getTargetConnection 方法:返回底层的 Connection 对象
				case "getTargetConnection" -> this.target;
				// 处理 unwrap 方法:返回底层连接或代理连接
				case "unwrap" ->
						(((Class<?>) args[0]).isInstance(proxy) ? proxy : this.target.unwrap((Class<?>) args[0]));
				// 处理 isWrapperFor 方法:判断是否是代理连接
				case "isWrapperFor" ->
						(((Class<?>) args[0]).isInstance(proxy) || this.target.isWrapperFor((Class<?>) args[0]));
				default -> {
					try {
						// 调用目标 Connection 的方法
						Object retVal = method.invoke(this.target, args);

						// 如果返回值是 JDBC Statement,应用语句设置(如 fetch size、max rows、超时等)
						if (retVal instanceof Statement statement) {
							applyStatementSettings(statement);
						}
						// 返回结果
						yield retVal;
					}
					catch (InvocationTargetException ex) {
						throw ex.getTargetException();
					}
				}
			};
		}
	}


	/**
	 * 一个简单的适配器,用于 PreparedStatementCreator,允许使用普通的 SQL 语句。
	 */
	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;
		}
	}


	/**
	 * 一个简单的适配器,用于 CallableStatementCreator,允许使用普通的 SQL 调用语句。
	 */
	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;
		}
	}


	/**
	 * 适配器,允许在 ResultSetExtractor 中使用 RowCallbackHandler。
	 * <p>使用普通的 ResultSet,因此在使用时需要小心:不要用来遍历 ResultSet,
	 * 否则可能会导致不可预测的后果。
	 */
	private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<@Nullable Object> {

		private final RowCallbackHandler rch;

		private final int maxRows;

		public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch, int maxRows) {
			this.rch = rch;
			this.maxRows = maxRows;
		}

		@Override
		public @Nullable Object extractData(ResultSet rs) throws SQLException {
			int processed = 0;
			while (rs.next() && (this.maxRows == -1 || (processed++) < this.maxRows)) {
				this.rch.processRow(rs);
			}
			return null;
		}
	}


	/**
	 * 用于将 ResultSet 转换为流(Stream)的 Spliterator 适配器。
	 * @since 5.3
	 */
	private static class ResultSetSpliterator<T> implements Spliterator<T> {

		private final ResultSet rs;

		private final RowMapper<T> rowMapper;

		private final int maxRows;

		private int rowNum = 0;

		public ResultSetSpliterator(ResultSet rs, RowMapper<T> rowMapper, int maxRows) {
			this.rs = rs;
			this.rowMapper = rowMapper;
			this.maxRows = maxRows;
		}

		@Override
		public boolean tryAdvance(Consumer<? super T> action) {
			try {
				if (this.rs.next() && (this.maxRows == -1 || this.rowNum < this.maxRows)) {
					action.accept(this.rowMapper.mapRow(this.rs, this.rowNum++));
					return true;
				}
				return false;
			}
			catch (SQLException ex) {
				throw new InvalidResultSetAccessException(ex);
			}
		}

		@Override
		public @Nullable Spliterator<T> trySplit() {
			return null;
		}

		@Override
		public long estimateSize() {
			return Long.MAX_VALUE;
		}

		@Override
		public int characteristics() {
			return Spliterator.ORDERED;
		}

		public Stream<T> stream() {
			return StreamSupport.stream(this, false);
		}
	}

}