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

相关推荐
SomeB1oody1 小时前
【Rust自学】11.3. 自定义错误信息
开发语言·后端·rust
SomeB1oody1 小时前
【Rust自学】11.6. 控制测试运行:并行和串行(连续执行)测试
开发语言·后端·rust
Q_27437851092 小时前
django基于Python的电影推荐系统
java·后端·python·django
ZERO空白2 小时前
spring task使用
java·后端·spring
潜洋2 小时前
Spring Boot教程之五十五:Spring Boot Kafka 消费者示例
spring boot·后端·kafka
customer083 小时前
【开源免费】基于SpringBoot+Vue.JS企业级工位管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
GISer_Jing3 小时前
React面试常见题目
前端·react.js·面试
庄小焱3 小时前
Mybatis——DDD项目中Mybatis开发步骤实战
后端
Asthenia04123 小时前
[SpringBoot]Spring如何启用依赖?@EnableAutoConfiguration与SpringFactoriesLoader来助你!
后端