当前位置: 首页 > news >正文

SpringJDBC源码初探-JdbcTemplate类

一、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 {@Nullableprivate DataSource dataSource;@Nullableprivate 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@Nullablepublic <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)
@Nullableprivate <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方法

@Nullablepublic <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@Nullablepublic 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. 返回结果
http://www.dtcms.com/a/288013.html

相关文章:

  • xss的利用
  • 博图SCL语言中常用运算符使用详解及实战案例(下)
  • 抖音回应:没有自建外卖,就是在团购的基础上增加的配送功能
  • 前端开发技巧:浏览器模拟弱网络环境
  • Streamlit 官翻 4 - 快速参考、知识库 Quick Reference
  • 电脑windows系统深度维护指南
  • 网络包从客户端发出到服务端接收的过程
  • 初识C++——开启新旅途
  • 【每日算法】专题十五_BFS 解决 FloodFill 算法
  • Xshell若依项目部署到云服务器
  • 考研408《计算机组成原理》复习笔记,第三章(5)——磁盘存储器
  • react+antd 可拖拽模态框组件
  • 智能设备畅想
  • AWD练习的平台搭建
  • 牛客-倒置字符串
  • 如何使用orthofinder进行同源基因鉴定
  • 【Web APIs】JavaScript 自定义属性操作 ② ( H5 自定义属性 )
  • Node.js dns 模块深入解析
  • python的第三方库的基本运用
  • node.js学习笔记1
  • Tomcat配置和部署项目
  • 从零手写红黑树(C++实现详解)
  • Java 中的继承与多态
  • 【OD机试】人民币转换
  • 小数点何去何从?教务系统成绩计算的精度与公平性博弈
  • Linux:lvs集群技术
  • 跨境卖家紧急自查,Endryko Karmadi四季版画版权维权
  • 单例模式的设计与实现
  • Helm常用命令大全(2025最新版)
  • 马拉车(Manacher)算法