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

相关推荐
Asthenia04121 小时前
Spring AOP 和 Aware:在Bean实例化后-调用BeanPostProcessor开始工作!在初始化方法执行之前!
后端
Asthenia04122 小时前
什么是消除直接左递归 - 编译原理解析
后端
Asthenia04122 小时前
什么是自上而下分析 - 编译原理剖析
后端
Asthenia04123 小时前
什么是语法分析 - 编译原理基础
后端
Asthenia04123 小时前
理解词法分析与LEX:编译器的守门人
后端
uhakadotcom3 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
拉不动的猪3 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪3 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
Asthenia04124 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端