spring JdbcTemplate的查询过程

前言

虽然JdbcTemplate基本上不会在项目中用到,但是通过阅读和学习它的源码,可以提升我们面对接口编程的能力。JdbcTemplate提供多种query和update方法用来方便地查询和更新数据。

使用示例:

java 复制代码
@Component
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public UserDao() {}

    public String getUserName() {
        User user = jdbcTemplate.queryForObject("select id,username,password from xxl_job_user where id = '1'", (rs, rowNum) -> {
            User temp = new User();
            temp.setId(rs.getInt("id"));
            temp.setName(rs.getString("username"));
            temp.setPassword(rs.getString("password"));
            return temp;
        });
        return user.getName();
    }
}

上述例子中,我们只要写好sql,再创建一个RowMapper接口的实现类对象,就成功从数据库中查到用户信息并封装成User对象。

查询流程

初始化StatementCallback

  1. 先将用户自定义的行映射器 (RowMapper)封装成结果集提取器 (ResultSetExtrator)
java 复制代码
	@Override
	public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
		return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
	}
  1. 再将sql字符串结果集提取器 封装成查询sql语句回调(QueryStatementCallback)。
java 复制代码
	@Override
	@Nullable
	public <T> T query(final String sql, final 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 + "]");
		}

		/**
		 * Callback to execute the query.
		 */
		class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
			@Override
			@Nullable
			public 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;
			}
		}

获取Statement

  1. 先获取一个数据源(DataSource对象)。
  2. 再通过数据源获取一个数据库连接(Connection对象)。
  3. 再通过数据库连接创建一个sql语句(Statement对象)
java 复制代码
	//-------------------------------------------------------------------------
	// Methods dealing with static SQL (java.sql.Statement)
	//-------------------------------------------------------------------------

	@Override
	@Nullable
	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.
			String sql = getSql(action);
			JdbcUtils.closeStatement(stmt);
			stmt = null;
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw translateException("StatementCallback", sql, ex);
		}
		finally {
			JdbcUtils.closeStatement(stmt);
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

执行StatementCallback的回调方法

  1. 执行sql语句得到**结果集**(ResultSet) 2. 将结果集作为参数,执行**结果集提取器**的extractData(),extractData()内部执行**行映射器**的mapRow(),将一行数据映射成对象。

总结

查询流程:

简单说:

  1. 先拿到Statement对象,Statement对象执行对应的sql得到结果集。
  2. 结果集提取器借助行映射器对结果集进行映射,得到对应的对象。

扩展

RowMapper、ResultSetExtrator、StatementCallback为什么要定义成泛型?

通过泛型将数据库返回的数据类型参数化,从而可以针对不同类型sql操作返回不同类型的对象。比如select语句,查询的表不一样,返回对象的类型也不一样,查询数据的数量不一样,返回的可以是单个对象,也可以是对象列表。又比如update语句,可以返回变更成功的数据个数,也可以返回是否变更成功,将返回数据的具体类型交给开发人员自行实现。

相关推荐
Wang's Blog16 小时前
Java框架快速入门: Spring Security+OAuth2之短信服务多供应商动态切换(阿里云与LeanCloud)
java·spring·阿里云
专业程序开发源16 小时前
springbootLivehouse票务系统-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·课程设计·pygame
PC2005_cloud16 小时前
Rust学习笔记:所有权、借用与生命周期——Rust的核心机制
前端·后端
蜗牛互联网16 小时前
语音AI开始边听边说,改变的不只是响应速度
java·人工智能·后端·语音识别
Mav16 小时前
[个人学习记录]从零构建高性能 LLM 推理网关:Go 语言 SSE 流式转发、级联取消与背压
后端
卓怡学长16 小时前
w233基于vue和springboot的宠物管理系统的设计与实现
java·vue.js·spring boot·spring·intellij-idea
狼爷16 小时前
磁盘IO打满怎么办?我用5个真实案例,总结了这套可复用的排查方法论
后端·性能优化
小羊在睡觉17 小时前
HLS视频
linux·后端·golang
苍何17 小时前
小米版 Codex,干活有点猛啊
后端
苍何17 小时前
直播!用 AI 实时生成游戏,速来看
后端