千家信息网

深入解析Spring架构与设计原理-数据库的操作实现

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,关于Spring JDBC还是从Spring JDBC说起吧,虽然现在应用很多都是直接使用Hibernate或者其他的ORM工具。但JDBC毕竟还是很基本的,其中的JdbcTemplate就是我们经常
千家信息网最后更新 2026年11月01日深入解析Spring架构与设计原理-数据库的操作实现

关于Spring JDBC
还是从Spring JDBC说起吧,虽然现在应用很多都是直接使用Hibernate或者其他的ORM工具。但JDBC毕竟还是很基本的,其中的JdbcTemplate就是我们经常使用的,比如JDBCTemplate的execute方法,就是一个基本的方法,在这个方法的实现中,可以看到对数据库操作的基本过程。


//execute方法执行的是输入的sql语句
public void execute(final String sql) throws DataAccessException {
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL statement [" + sql + "]");
}
class ExecuteStatementCallback implements StatementCallback, SqlProvider {
public Object doInStatement(Statement stmt) throws SQLException {
stmt.execute(sql);
return null;
}
public String getSql() {
return sql;
}
}
execute(new ExecuteStatementCallback());
}
//这是使用java.sql.Statement处理静态SQL语句的方法
public T execute(StatementCallback action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
//这里取得数据库的Connection,这个数据库的Connection已经在Spring的事务管理之下
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
//创建Statement
stmt = conToUse.createStatement();
applyStatementSettings(stmt);
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
//这里调用回调函数
T result = action.doInStatement(stmtToUse);
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.
//如果捕捉到数据库异常,把数据库Connection释放,同时抛出一个经过Spring转换过的Spring数据库异常
//Spring做了一项有意义的工作,就是把这些数据库异常统一到自己的异常体系里了
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
}
finally {
JdbcUtils.closeStatement(stmt);
//释放数据库connection
DataSourceUtils.releaseConnection(con, getDataSource());
}
}


在使用数据库的时候,有一个很重要的地方就是对数据库连接的管理,在这里,是由DataSourceUtils来完成的。Spring通过这个辅助类来对数据的Connection进行管理。比如通过它来完成打开和关闭Connection等操作。DataSourceUtils对这些数据库Connection管理的实现, 如以下代码所示。


//这是取得数据库连接的调用,实现是通过调用doGetConnection完成的,这里执行了异常的转换操作
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
}
}
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//把对数据库的Connection放到事务管理中进行管理,这里使用TransactionSynchronizationManager中定义的ThreadLocal变量来和线程绑定数据库连接
//如果在TransactionSynchronizationManager中已经有与当前线程绑定数据库连接,那就直接取出来使用
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
// 这里得到需要的数据库Connection,在Bean配置文件中定义好的,
// 同时最后把新打开的数据库Connection通过TransactionSynchronizationManager和当前线程绑定起来。
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = dataSource.getConnection();

if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
}


关于数据库操作类RDBMS
从JdbcTemplate中,我们看到,他提供了许多简单查询和更新的功能。但是,如果需要更高层次的抽象,以及更面向对象的方法来访问数据库,Spring为我们提供了org.springframework.jdbc.object包,里面包含了SqlQuery、SqlMappingQuery、SqlUpdate和StoredProcedure等类,这些类都是Spring JDBC应用程序可以使用的。但要注意,在使用这些类时需要为它们配置好JdbcTemplate作为其基本的操作实现,因为在它们的功能实现中,对数据库操作的那部分实现基本上还是依赖于JdbcTemplate来完成的。

比如,对MappingSqlQuery使用的过程,是非常简洁的;在设计好数据的映射代码之后,查询得到的记录已经按照前面的设计转换为对象List了,一条查询记录对应于一个数据对象,可以把数据库的数据记录直接映射成Java对象在程序中使用,同时又可避免使用第三方ORM工具的配置,对于简单的数据映射场合是非常方便的;在mapRow方法的实现中提供的数据转换规则,和我们使用Hibernate时,Hibernate的hbm文件起到的作用是非常类似的。这个MappingSqlQuery需要的对设置进行compile,这些compile是这样完成的,如以下代码所示:


protected final void compileInternal() {
//这里是对参数的compile过程,所有的参数都在getDeclaredParameters里面,生成了一个PreparedStatementCreatorFactory
this.preparedStatementFactory = new PreparedStatementCreatorFactory(getSql(), getDeclaredParameters());
this.preparedStatementFactory.setResultSetType(getResultSetType());
this.preparedStatementFactory.setUpdatableResults(isUpdatableResults());
this.preparedStatementFactory.setReturnGeneratedKeys(isReturnGeneratedKeys());
if (getGeneratedKeysColumnNames() != null) {
this.preparedStatementFactory.setGeneratedKeysColumnNames(getGeneratedKeysColumnNames());
}
his.preparedStatementFactory.setNativeJdbcExtractor(getJdbcTemplate().getNativeJdbcExtractor());
onCompileInternal();
}


在执行查询时,执行的实际上是SqlQuery的executeByNamedParam方法,这个方法需要完成的工作包括配置SQL语句,配置数据记录到数据对象的转换的RowMapper,然后使用JdbcTemplate来完成数据的查询,并启动数据记录到Java数据对象的转换,如以下代码所示:


public List executeByNamedParam(Map paramMap, Map context) throws DataAccessException {
validateNamedParameters(paramMap);
//得到需要执行的SQL语句
ParsedSql parsedSql = getParsedSql();
MapSqlParameterSource paramSource = new MapSqlParameterSource(paramMap);
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
//配置好SQL语句需要的Parameters及rowMapper,这个rowMapper完成数据记录到对象的转换
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, getDeclaredParameters());
RowMapper rowMapper = newRowMapper(params, context);
//我们又看到了JdbcTemplate,这里使用JdbcTemplate来完成对数据库的查询操作,所以我们说JdbcTemplate是非常基本的操作类
return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, params), rowMapper);
}


在Spring对JDBC的操作中,基本上是对JDBC/Hibernate基础上API的封装。这些封装可以直接使用,也可以在IoC容器中配置好了再使用,当结合IoC容器的基础上进行使用的时候,可以看到许多和事务管理相关的处理部分,都是非常值得学习的,在那里,可以看到对数据源的管理 - Hibernate中session的管理,与线程的结合等等。

更多内容请关注微信公众号:IT哈哈(it_haha)


数据 数据库 方法 管理 对象 配置 查询 语句 代码 就是 线程 事务 事务管理 同时 过程 设计 功能 参数 基础 容器 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广东猪兼强互联网科技有限公司 上海卓越科技互联网 互联网通讯科技 朗新科技与工业互联网 互联网科技战争 壹账通互联网科技 丰台科技园 互联网 苏州大垚互联网科技 哈尔滨新华互联网科技学院 互联网媒体平台算高科技产业 电子科技大学互联网创业大赛 深圳育鹏互联网科技有限公司招聘 长沙茂晟互联网科技有限公司 特约风豹互联网科技为什么扣费 互联网金融科技名词解释 互联网科技实习生岗位 易企秀互联网科技是做什么的 互联网高科技行业有哪些企业 互联网的黑科技实验室 小牛互联网科技有限公司地址 互联网是第几次科技革命的成果 中国互联网科技工作委员会毛军 沃里互联网科技 互联网科技小额贷款 银川新华互联网科技学校地址 互联网金融科技公司干啥的 哈尔滨屹滨互联网科技有限公司 银行科技岗属于互联网吗 互联网营销推广黑科技 科技互联网公司两年变化
0