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语句,可以返回变更成功的数据个数,也可以返回是否变更成功,将返回数据的具体类型交给开发人员自行实现。

相关推荐
Vitalia21 分钟前
从零开始学 Rust:基本概念——变量、数据类型、函数、控制流
开发语言·后端·rust
猎人everest3 小时前
SpringBoot应用开发入门
java·spring boot·后端
孤雪心殇9 小时前
简单易懂,解析Go语言中的Map
开发语言·数据结构·后端·golang·go
White graces9 小时前
正则表达式效验邮箱格式, 手机号格式, 密码长度
前端·spring boot·spring·正则表达式·java-ee·maven·intellij-idea
菠菠萝宝9 小时前
【Java八股文】10-数据结构与算法面试篇
java·开发语言·面试·红黑树·跳表·排序·lru
A_one201010 小时前
前端开发常见问题与面试-02
面试·职场和发展
是姜姜啊!10 小时前
redis的应用,缓存,分布式锁
java·redis·spring
小突突突10 小时前
模拟实现Java中的计时器
java·开发语言·后端·java-ee
web1376560764310 小时前
Scala的宝藏库:探索常用的第三方库及其应用
开发语言·后端·scala
闲猫11 小时前
go 反射 interface{} 判断类型 获取值 设置值 指针才可以设置值
开发语言·后端·golang·反射