Spring JDBC 源码深度解析

55 阅读7分钟

Spring JDBC 源码深度解析

Spring JDBC 是 Spring 框架提供的用于简化 JDBC 操作的核心模块,它通过模板方法模式消除了传统 JDBC 编程中的大量样板代码,使开发者能够专注于 SQL 逻辑和业务处理。本文将深入分析 Spring JDBC 的核心组件、实现原理和设计思想。

一、整体架构设计

Spring JDBC 模块主要分为以下几个核心层次:

  1. 数据访问层抽象:提供统一的数据访问异常体系
  2. 模板层:核心模板类封装常见操作
  3. 支持层:提供各种辅助功能和工具类

主要类图关系:

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 的查询操作为例,完整的执行流程如下:

  1. 获取连接:通过 DataSourceUtils 获取数据库连接
  2. 创建语句:根据 SQL 创建 PreparedStatement
  3. 设置参数:设置 SQL 参数值
  4. 执行查询:调用 Statement.executeQuery()
  5. 结果映射:通过 RowMapper 将结果集映射为 Java 对象
  6. 异常处理:捕获 SQLException 并转换为 DataAccessException
  7. 资源释放:释放 ResultSet、Statement 和 Connection

六、关键设计模式

  1. 模板方法模式:JdbcTemplate 封装了通用流程,通过回调接口暴露可变部分
  2. 策略模式:RowMapper、SQLExceptionTranslator 等接口的不同实现提供不同策略
  3. 工厂模式:PreparedStatementCreator 用于创建 PreparedStatement
  4. 装饰器模式:各种 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
);

八、性能优化机制

  1. 连接管理优化:通过 DataSourceUtils 实现连接的获取和释放优化
  2. 批处理支持:提供 batchUpdate 方法执行批量操作
  3. 预编译语句缓存:在某些 DataSource 实现中提供语句缓存
  4. 结果集处理优化:fetchSize 和 maxRows 参数控制结果集加载

九、总结

Spring JDBC 通过模板方法模式和回调接口,成功地简化了 JDBC 编程,消除了样板代码,同时提供了丰富的功能和灵活的扩展点。其核心价值在于:

  1. 自动化资源管理:自动处理连接、语句和结果集的创建和释放
  2. 统一异常处理:将 SQLException 转换为运行时异常
  3. 灵活的映射机制:支持多种结果映射方式
  4. 强大的事务支持:提供编程式和声明式事务管理
  5. 与 Spring 框架无缝集成:利用依赖注入和 AOP 等核心特性

Spring JDBC 虽然不像 ORM 框架那样提供对象关系映射功能,但它的简单性、灵活性和对 SQL 的完全控制使其成为许多应用的理想选择,特别是对于需要精细控制 SQL 执行的场景。