Spring JDBC 源码深度解析
Spring JDBC 是 Spring 框架提供的用于简化 JDBC 操作的核心模块,它通过模板方法模式消除了传统 JDBC 编程中的大量样板代码,使开发者能够专注于 SQL 逻辑和业务处理。本文将深入分析 Spring JDBC 的核心组件、实现原理和设计思想。
一、整体架构设计
Spring JDBC 模块主要分为以下几个核心层次:
- 数据访问层抽象:提供统一的数据访问异常体系
- 模板层:核心模板类封装常见操作
- 支持层:提供各种辅助功能和工具类
主要类图关系:
JdbcOperations (接口)
↑
|
JdbcTemplate (实现)
↑
|
JdbcAccessor (抽象基类)
|
+-- DataSource
|
+-- SQLExceptionTranslator
二、核心组件源码解析
1. JdbcAccessor 抽象基类
JdbcAccessor 是 JdbcTemplate 的抽象基类,提供了数据源管理和异常转换等基础功能。
public abstract class JdbcAccessor implements InitializingBean {
private DataSource dataSource;
private SQLExceptionTranslator exceptionTranslator;
private boolean lazyInit = true;
@Override
public void afterPropertiesSet() {
if (getDataSource() == null) {
throw new IllegalArgumentException("Property 'dataSource' is required");
}
if (!isLazyInit()) {
getExceptionTranslator();
}
}
// getter和setter方法
}
这个基类实现了 InitializingBean 接口,确保在 Bean 初始化时验证 DataSource 是否已经设置。它还管理 SQLExceptionTranslator 用于异常转换。
2. JdbcTemplate 核心实现
JdbcTemplate 是 Spring JDBC 的核心类,实现了 JdbcOperations 接口,提供了丰富的数据库操作方法。
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
// 查询超时设置
private int queryTimeout = -1;
// 结果集获取大小
private int fetchSize = -1;
// 最大行数
private int maxRows = -1;
// SQL警告处理设置
private boolean ignoreWarnings = true;
private boolean skipResultsProcessing = false;
private boolean skipUndeclaredResults = false;
// 初始化异常转换器
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (getExceptionTranslator() == null) {
setExceptionTranslator(new SQLErrorCodeSQLExceptionTranslator(getDataSource()));
}
}
// 核心更新方法示例
@Override
public int update(final String sql) {
return update(sql, (Object[]) null);
}
@Override
public int update(final String sql, final Object... args) {
return update(sql, newArgPreparedStatementSetter(args));
}
@Override
public int update(final String sql, final PreparedStatementSetter pss) throws DataAccessException {
return update(new SimplePreparedStatementCreator(sql), pss);
}
// 内部核心执行方法
protected <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
// 获取连接、创建语句、执行回调、资源释放等逻辑
Connection con = DataSourceUtils.getConnection(getDataSource());
PreparedStatement ps = null;
try {
Connection conToUse = con;
ps = psc.createPreparedStatement(conToUse);
applyStatementSettings(ps);
T result = action.doInPreparedStatement(ps);
handleWarnings(ps);
return result;
} catch (SQLException ex) {
// 异常转换
String sql = getSql(psc);
JdbcUtils.closeStatement(ps);
ps = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("PreparedStatementCallback", sql, ex);
} finally {
// 资源释放
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
}
JdbcTemplate 采用模板方法设计模式,将数据库操作的通用流程(如获取连接、创建语句、异常处理、资源释放)封装在模板方法中,而将可变的部分(如具体的 SQL 执行逻辑)通过回调接口委托给用户实现。
3. JdbcOperations 接口
JdbcOperations 接口定义了所有 JDBC 操作方法,是 JdbcTemplate 的行为契约。
public interface JdbcOperations {
// 更新操作
int update(String sql) throws DataAccessException;
int update(String sql, Object... args) throws DataAccessException;
int update(String sql, PreparedStatementSetter pss) throws DataAccessException;
// 批处理操作
int[] batchUpdate(String... sql) throws DataAccessException;
int[] batchUpdate(String sql, List<Object[]> batchArgs) throws DataAccessException;
// 查询操作
<T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException;
<T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException;
<T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException;
// 其他操作
void execute(String sql) throws DataAccessException;
<T> T execute(StatementCallback<T> action) throws DataAccessException;
<T> T execute(ConnectionCallback<T> action) throws DataAccessException;
}
4. SQLExceptionTranslator 异常转换机制
Spring JDBC 提供了异常转换机制,将 JDBC 的 SQLException 转换为 Spring 的 DataAccessException 体系。
public interface SQLExceptionTranslator {
DataAccessException translate(String task, String sql, SQLException ex);
}
// 具体实现类
public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExceptionTranslator {
@Override
protected DataAccessException doTranslate(String task, String sql, SQLException ex) {
// 根据SQL错误码翻译为具体的DataAccessException子类
int errorCode = ex.getErrorCode();
// 各种错误码判断和异常转换逻辑
}
}
5. RowMapper 行映射机制
RowMapper 接口用于将结果集中的行映射到 Java 对象。
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
// 使用示例
RowMapper<Actor> actorMapper = (rs, rowNum) -> new Actor(
rs.getString("first_name"),
rs.getString("last_name")
);
三、事务管理机制
1. PlatformTransactionManager 事务管理器
PlatformTransactionManager 是事务管理的核心接口,定义了事务操作的基本方法。
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
对于 JDBC,Spring 提供了 DataSourceTransactionManager 实现:
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
private DataSource dataSource;
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(getDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 获取连接并设置事务属性
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = getDataSource().getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 设置事务隔离级别和只读属性
// ...
// 开始事务
con.setAutoCommit(false);
// 激活事务同步
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
catch (SQLException ex) {
// 异常处理
}
}
// doCommit 和 doRollback 方法实现
}
2. TransactionTemplate 编程式事务
TransactionTemplate 提供了编程式事务管理的支持:
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
private PlatformTransactionManager transactionManager;
@Override
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
} catch (RuntimeException ex) {
// 异常时回滚
rollbackOnException(status, ex);
throw ex;
} catch (Error err) {
// 错误时回滚
rollbackOnException(status, err);
throw err;
} catch (Exception ex) {
// 检查是否为可回滚异常
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 提交事务
this.transactionManager.commit(status);
return result;
}
}
3. TransactionCallback 回调接口
public interface TransactionCallback<T> {
T doInTransaction(TransactionStatus status);
}
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
四、扩展组件
1. NamedParameterJdbcTemplate 命名参数支持
NamedParameterJdbcTemplate 扩展了 JdbcTemplate,支持命名参数绑定,比位置参数更具可读性和可维护性。
public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {
private final JdbcTemplate classicJdbcTemplate;
@Override
public int update(String sql, SqlParameterSource paramSource) throws DataAccessException {
ParsedSql parsedSql = getParsedSql(sql);
SqlParameterSource sqlParamSource = new ArgumentSqlParameterSource(paramSource);
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(
sql, parsedSql.getParameterNames(), sqlParamSource.getSqlTypes());
pscf.setResultSetType(getResultSetType());
pscf.setUpdatableResults(isUpdatableResults());
pscf.setReturnGeneratedKeys(isReturnGeneratedKeys());
if (getGeneratedKeysColumnNames() != null) {
pscf.setGeneratedKeysColumnNames(getGeneratedKeysColumnNames());
}
PreparedStatementCreator psc = pscf.newPreparedStatementCreator(sqlParamSource);
if (logger.isDebugEnabled()) {
logger.debug("Executing prepared SQL update using SqlParameterSource: " + sql);
}
return this.classicJdbcTemplate.update(psc);
}
// 其他方法实现
}
2. SimpleJdbcTemplate (已废弃)
SimpleJdbcTemplate 是为 Java 5+ 设计的简化版本,利用泛型和可变参数提供更简洁的 API,但在 Spring 3.1 后已被标记为废弃,因为其功能已被合并到 JdbcTemplate 中。
五、核心执行流程
以 JdbcTemplate 的查询操作为例,完整的执行流程如下:
- 获取连接:通过 DataSourceUtils 获取数据库连接
- 创建语句:根据 SQL 创建 PreparedStatement
- 设置参数:设置 SQL 参数值
- 执行查询:调用 Statement.executeQuery()
- 结果映射:通过 RowMapper 将结果集映射为 Java 对象
- 异常处理:捕获 SQLException 并转换为 DataAccessException
- 资源释放:释放 ResultSet、Statement 和 Connection
六、关键设计模式
- 模板方法模式:JdbcTemplate 封装了通用流程,通过回调接口暴露可变部分
- 策略模式:RowMapper、SQLExceptionTranslator 等接口的不同实现提供不同策略
- 工厂模式:PreparedStatementCreator 用于创建 PreparedStatement
- 装饰器模式:各种 JdbcOperations 的实现和扩展
七、使用示例
1. JdbcTemplate 基本用法
// 创建数据源和JdbcTemplate
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// 插入数据
jdbcTemplate.update("INSERT INTO users (name, email) VALUES (?, ?)", "张三", "zhangsan@example.com");
// 更新数据
jdbcTemplate.update("UPDATE users SET email = ? WHERE name = ?", "zhangsan_new@example.com", "张三");
// 删除数据
jdbcTemplate.update("DELETE FROM users WHERE name = ?", "张三");
// 查询单个值
int count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", Integer.class);
// 查询对象
User user = jdbcTemplate.queryForObject(
"SELECT id, name, email FROM users WHERE id = ?",
new Object[]{1},
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
)
);
// 查询列表
List<User> users = jdbcTemplate.query(
"SELECT id, name, email FROM users",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
)
);
2. TransactionTemplate 编程式事务
// 创建事务管理器
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
// 创建事务模板
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
transactionTemplate.setTimeout(30);
// 执行事务操作
transactionTemplate.execute(status -> {
try {
// 转账操作
jdbcTemplate.update("UPDATE accounts SET balance = balance - ? WHERE account_id = ?", 100, "account1");
jdbcTemplate.update("UPDATE accounts SET balance = balance + ? WHERE account_id = ?", 100, "account2");
return true;
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
3. NamedParameterJdbcTemplate 使用
// 创建命名参数JdbcTemplate
NamedParameterJdbcTemplate namedJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
// 使用Map传递参数
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("name", "李四");
paramMap.put("email", "lisi@example.com");
namedJdbcTemplate.update(
"INSERT INTO users (name, email) VALUES (:name, :email)",
paramMap
);
// 使用SqlParameterSource传递参数
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(user);
namedJdbcTemplate.update(
"UPDATE users SET name = :name, email = :email WHERE id = :id",
paramSource
);
八、性能优化机制
- 连接管理优化:通过 DataSourceUtils 实现连接的获取和释放优化
- 批处理支持:提供 batchUpdate 方法执行批量操作
- 预编译语句缓存:在某些 DataSource 实现中提供语句缓存
- 结果集处理优化:fetchSize 和 maxRows 参数控制结果集加载
九、总结
Spring JDBC 通过模板方法模式和回调接口,成功地简化了 JDBC 编程,消除了样板代码,同时提供了丰富的功能和灵活的扩展点。其核心价值在于:
- 自动化资源管理:自动处理连接、语句和结果集的创建和释放
- 统一异常处理:将 SQLException 转换为运行时异常
- 灵活的映射机制:支持多种结果映射方式
- 强大的事务支持:提供编程式和声明式事务管理
- 与 Spring 框架无缝集成:利用依赖注入和 AOP 等核心特性
Spring JDBC 虽然不像 ORM 框架那样提供对象关系映射功能,但它的简单性、灵活性和对 SQL 的完全控制使其成为许多应用的理想选择,特别是对于需要精细控制 SQL 执行的场景。