spring boot · 2024-04-30 0

SpringBoot 的 DataSource、JdbcTemplate、DataSourceTransactionManager 加载原理

一、环境

1.maven 依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
</dependencies>

2.配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/temp
    username: root
    password: 123456

二、示例

@SpringBootApplication
public class Boot {

    public static void main(String[] args) {
        SpringApplication.run(Boot.class, args);
    }
}

使用 JdbcTemplate

@Component
public class MyApplicationRunner1 implements ApplicationRunner {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void run(ApplicationArguments args) throws Exception {
         String sql = "SELECT * FROM student";
         List<Map<String, Object>> result = jdbcTemplate.queryForList(sql);
         System.out.println(result);
    }
}

使用 JdbcTemplate 和 DataSourceTransactionManager,实现事务

@Component
public class MyApplicationRunner implements ApplicationRunner {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private DataSourceTransactionManager transactionManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        String sql = "INSERT INTO student VALUES(1, 'jdbcTemplate1')";

        // 开启事务
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);
        // TransactionStatus status = transactionManager.getTransaction(TransactionDefinition.withDefaults());

        try {
            jdbcTemplate.execute(sql);
            int o = 1 / 0;
            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滚事务
            transactionManager.rollback(status);
        }
    }
}

三、DataSource 加载原理

1.加载 DataSourceAutoConfiguration

spring-boot-autoconfigure-2.7.2.jar 下有文件:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

根据 META-INF 下文件,会加载 DataSourceAutoConfiguration

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

2.加载 DataSourceProperties 和 DataSource

根据 DataSourceAutoConfiguration 会加载 DataSourceProperties 和 DataSource, 其中 DataSource 是 DataSourceConfiguration.Hikari.class

@AutoConfiguration(before = SqlInitializationAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import(DataSourcePoolMetadataProvidersConfiguration.class)
public class DataSourceAutoConfiguration {
    ...
    @Configuration(proxyBeanMethods = false)
    @Conditional(PooledDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
            DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
            DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
    protected static class PooledDataSourceConfiguration {

    }
    ...
}
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {

    private String name;

    private String driverClassName;

    private String url;

    private String username;

    private String password;

    ...
}
abstract class DataSourceConfiguration {
    ...
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(HikariDataSource.class)
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
            matchIfMissing = true)
    static class Hikari {

        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.hikari")
        HikariDataSource dataSource(DataSourceProperties properties) {
            HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }
            return dataSource;
        }

    }
    ...
}

四、JdbcTemplate 加载原理

1.加载 JdbcTemplateAutoConfiguration

spring-boot-autoconfigure-2.7.2.jar 下有文件:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

根据 META-INF 下文件,会加载 DataSourceAutoConfiguration

org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration

2.加载 JdbcProperties、JdbcTemplateConfiguration

根据 JdbcTemplateAutoConfiguration,加载 JdbcProperties、JdbcTemplateConfiguration 和 DataSourceAutoConfiguration

@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ DatabaseInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,
        NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {

}
@ConfigurationProperties(prefix = "spring.jdbc")
public class JdbcProperties {

    private final Template template = new Template();

    public Template getTemplate() {
        return this.template;
    }

    public static class Template {

        private int fetchSize = -1;

        private int maxRows = -1;

        @DurationUnit(ChronoUnit.SECONDS)
        private Duration queryTimeout;

        ...
    }

}

3.加载 JdbcTemplate

根据 JdbcTemplateConfiguration 会加载 JdbcTemplate
实例化 JdbcTemplate,需要 DataSource 和 JdbcProperties

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {

    @Bean
    @Primary
    JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        JdbcProperties.Template template = properties.getTemplate();
        jdbcTemplate.setFetchSize(template.getFetchSize());
        jdbcTemplate.setMaxRows(template.getMaxRows());
        if (template.getQueryTimeout() != null) {
            jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
        }
        return jdbcTemplate;
    }

}

4.JdbcTemplate 执行 sql

JdbcTemplate 执行 sql,获得连接

JdbcTemplate 调用 DataSourceUtils.getConnection(obtainDataSource()) 获得连接,调用 DataSourceUtils.releaseConnection(con, getDataSource()) 释放连接

// JdbcTemplate.java
@Override
public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
    return query(sql, getColumnMapRowMapper());
}

@Override
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
    return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
}

@Override
@Nullable
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
    ...
    return execute(new QueryStatementCallback(), true);
}

@Nullable
private <T> T execute(StatementCallback<T> action, boolean closeResources) throws DataAccessException {
    ...
    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) {
        ...
    }
    finally {
        if (closeResources) {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }
}

DataSourceUtils 调用 TransactionSynchronizationManager.getResource(dataSource) 获得连接,若没有连接,则调用 dataSource.getConnection(),获得连接

此处因之前未在 TransactionSynchronizationManager 中设置过连接,故 TransactionSynchronizationManager.getResource(dataSource) 获得连接为空

(如使用过 DataSourceTransactionManager 开始事务,则会在 TransactionSynchronizationManager 中保存连接)

// DataSourceUtils.java
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
    ...
    return doGetConnection(dataSource);
}

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    ...
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
        conHolder.requested();
        if (!conHolder.hasConnection()) {
            conHolder.setConnection(fetchConnection(dataSource));
        }
        return conHolder.getConnection();
    }

    Connection con = fetchConnection(dataSource);

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
        try {
            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;
}

private static Connection fetchConnection(DataSource dataSource) throws SQLException {
    Connection con = dataSource.getConnection();
    ...
    return con;
}

public static void releaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) {
    doReleaseConnection(con, dataSource);
    ...
}

public static void doReleaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) throws SQLException {
    if (con == null) {
        return;
    }
    if (dataSource != null) {
        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if (conHolder != null && connectionEquals(conHolder, con)) {
            conHolder.released();
            return;
        }
    }
    doCloseConnection(con, dataSource);
}
// TransactionSynchronizationManager.java
private static final ThreadLocal<Map<Object, Object>> resources =
        new NamedThreadLocal<>("Transactional resources");

@Nullable
public static Object getResource(Object key) {
    Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
    return doGetResource(actualKey);
}

@Nullable
private static Object doGetResource(Object actualKey) {
    Map<Object, Object> map = resources.get();
    if (map == null) {
        return null;
    }
    Object value = map.get(actualKey);
    if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
        map.remove(actualKey);
        if (map.isEmpty()) {
            resources.remove();
        }
        value = null;
    }
    return value;
}

五、DataSourceTransactionManager 加载原理

1.加载 DataSourceTransactionManagerAutoConfiguration

spring-boot-autoconfigure-2.7.2.jar 下有文件:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

根据 META-INF 下文件,会加载 DataSourceTransactionManagerAutoConfiguration

org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration

2.加载 DataSourceProperties 和 DataSourceTransactionManager

DataSourceTransactionManagerAutoConfiguration 会加载 DataSourceProperties,默认是 JdbcTransactionManager

// DataSourceTransactionManagerAutoConfiguration.java
@AutoConfiguration
@ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnSingleCandidate(DataSource.class)
    static class JdbcTransactionManagerConfiguration {

        @Bean
        @ConditionalOnMissingBean(TransactionManager.class)
        DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,
                ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
            DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
            transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
            return transactionManager;
        }

        private DataSourceTransactionManager createTransactionManager(Environment environment, DataSource dataSource) {
            return environment.getProperty("spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE)
                    ? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource);
        }

    }

}

3.开启事务

DataSourceTransactionManager 的 getTransaction,开启事务

先调用 TransactionSynchronizationManager.getResource(obtainDataSource() 获得 ConnectionHolder,
若不存在,则使用 obtainDataSource().getConnection() 获得连接,
再调用 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()),把 ConnectionHolder 保存进 TransactionSynchronizationManager

// DataSourceTransactionManager.java
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
        throws TransactionException {

    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

    Object transaction = doGetTransaction();
    ...
    if (isExistingTransaction(transaction)) {
        return handleExistingTransaction(def, transaction, debugEnabled);
    }
    ...
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        ...
    }
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
        ...
        return startTransaction(def, transaction, debugEnabled, suspendedResources);
        ...
    }
    else {
        ...
    }
}

@Override
protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    ConnectionHolder conHolder =
            (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

@Override
protected boolean isExistingTransaction(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
        boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    DefaultTransactionStatus status = newTransactionStatus(
            definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    doBegin(transaction, definition);
    prepareSynchronization(status, definition);
    return status;
}

@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;

    try {
        if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            Connection newCon = obtainDataSource().getConnection();
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();

        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
        txObject.setReadOnly(definition.isReadOnly());

        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            con.setAutoCommit(false);
        }

        prepareTransactionalConnection(con, definition);
        txObject.getConnectionHolder().setTransactionActive(true);
        ...
        if (txObject.isNewConnectionHolder()) {
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }
    ...
}

TransactionSynchronizationManager 的 bindResource 绑定 DataSource 和 ConnectionHolder

// TransactionSynchronizationManager,java
private static final ThreadLocal<Map<Object, Object>> resources =
        new NamedThreadLocal<>("Transactional resources");

public static void bindResource(Object key, Object value) throws IllegalStateException {
    Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
    Assert.notNull(value, "Value must not be null");
    Map<Object, Object> map = resources.get();
    // set ThreadLocal Map if none found
    if (map == null) {
        map = new HashMap<>();
        resources.set(map);
    }
    Object oldValue = map.put(actualKey, value);
    // Transparently suppress a ResourceHolder that was marked as void...
    if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
        oldValue = null;
    }
    if (oldValue != null) {
        throw new IllegalStateException(
                "Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread");
    }
}

4.JdbcTemplate 执行 sql

JdbcTemplate 调用 DataSourceUtils.getConnection(obtainDataSource()) 获得连接,调用 DataSourceUtils.releaseConnection(con, getDataSource()) 释放连接

// JdbcTemplate.java
@Override
public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
    return query(sql, getColumnMapRowMapper());
}

@Override
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
    return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
}

@Override
@Nullable
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
    ...
    return execute(new QueryStatementCallback(), true);
}

@Nullable
private <T> T execute(StatementCallback<T> action, boolean closeResources) throws DataAccessException {
    ...
    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) {
        ...
    }
    finally {
        if (closeResources) {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }
}

DataSourceUtils 调用 TransactionSynchronizationManager.getResource(dataSource) 获得连接

// DataSourceUtils.java
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
    ...
    return doGetConnection(dataSource);
}

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    ...
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
        conHolder.requested();
        if (!conHolder.hasConnection()) {
            conHolder.setConnection(fetchConnection(dataSource));
        }
        return conHolder.getConnection();
    }

    Connection con = fetchConnection(dataSource);

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
        try {
            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;
}

public static void doReleaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) throws SQLException {
    if (con == null) {
        return;
    }
    if (dataSource != null) {
        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if (conHolder != null && connectionEquals(conHolder, con)) {
            // It's the transactional Connection: Don't close it.
            conHolder.released();
            return;
        }
    }
    doCloseConnection(con, dataSource);
}
// ConnectionHolder.java
public Connection getConnection() {
    if (this.currentConnection == null) {
        this.currentConnection = this.connectionHandle.getConnection();
    }
    return this.currentConnection;
}

@Override
public void released() {
    super.released();
    if (!isOpen() && this.currentConnection != null) {
        if (this.connectionHandle != null) {
            this.connectionHandle.releaseConnection(this.currentConnection);
        }
        this.currentConnection = null;
    }
}
// ResourceHolderSupport.java
public void released() {
    this.referenceCount--;
}

5.提交事务

调用 Connection 提交事务后,TransactionSynchronizationManager 的 unbindResource 移除 DataSource 和 ConnectionHolder 的绑定

// DataSourceTransactionManager.java
@Override
public final void commit(TransactionStatus status) throws TransactionException {
    ...
    processCommit(defStatus);
}

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
        boolean beforeCompletionInvoked = false;

        try {
            ...
            if (status.hasSavepoint()) {
                ...
            }
            else if (status.isNewTransaction()) {
                ...
                unexpectedRollback = status.isGlobalRollbackOnly();
                doCommit(status);
            }
            else if (isFailEarlyOnGlobalRollbackOnly()) {
                unexpectedRollback = status.isGlobalRollbackOnly();
            }
            ...
        }
        ...
    }
    finally {
        cleanupAfterCompletion(status);
    }
}

@Override
protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    ...
    try {
        con.commit();
    }
    ...
}

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    status.setCompleted();
    ...
    if (status.isNewTransaction()) {
        doCleanupAfterCompletion(status.getTransaction());
    }
    ...
}

@Override
protected void doCleanupAfterCompletion(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

    if (txObject.isNewConnectionHolder()) {
        TransactionSynchronizationManager.unbindResource(obtainDataSource());
    }
    ...
}
// TransactionSynchronizationManager.java
public static Object unbindResource(Object key) throws IllegalStateException {
    Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
    Object value = doUnbindResource(actualKey);
    ...
    return value;
}

@Nullable
private static Object doUnbindResource(Object actualKey) {
    Map<Object, Object> map = resources.get();
    if (map == null) {
        return null;
    }
    Object value = map.remove(actualKey);
    if (map.isEmpty()) {
        resources.remove();
    }
    ...
    return value;
}

6.回滚事务

// DataSourceTransactionManager.java
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
    ...
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    processRollback(defStatus, false);
}

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
        ...
        try {
            if (status.hasSavepoint()) {
                status.rollbackToHeldSavepoint();
            }
            else if (status.isNewTransaction()) {
                doRollback(status);
            }
            else {
                ...
            }
        }
        ...
    }
    finally {
        cleanupAfterCompletion(status);
    }
}

@Override
protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    ...
    try {
        con.rollback();
    }
    ....
}

六、总结

JdbcTemplate 保存着 DataSource,DataSourceTransactionManager 保存着 DataSource,TransactionSynchronizationManager 保存线程隔离的 DataSource 和 ConnectionHolder

JdbcTemplate 与 DataSourceUtils 关联,DataSourceUtils 与 TransactionSynchronizationManager 关联,DataSourceTransactionManager 与 TransactionSynchronizationManager 关联

在调用 DataSourceTransactionManager 的开启事务方法后,才会进行调用TransactionSynchronizationManager 绑定的功能

无事务管理器开启事务时,执行 sql:

  1. JdbcTemplate 调用 DataSourceUtils.getConnection(obtainDataSource())
  2. DataSourceUtils 调用 TransactionSynchronizationManager.getResource(dataSource) 获得连接,若没有连接,则调用 dataSource.getConnection(),获得连接

有事务管理器开启事务时,执行 sql:

  1. 开启事务时,DataSourceTransactionManager 的 getTransaction,开启事务,先调用 TransactionSynchronizationManager.getResource(obtainDataSource() 获得 ConnectionHolder,
    若不存在,则使用 obtainDataSource().getConnection() 获得连接,
    再调用 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()),把 ConnectionHolder 保存进 TransactionSynchronizationManager
  2. 执行sql,JdbcTemplate 调用 DataSourceUtils.getConnection(obtainDataSource())
  3. DataSourceUtils 调用 TransactionSynchronizationManager.getResource(dataSource) 获得连接
    4.调用 Connection 提交事务后或事务回滚后,调用 TransactionSynchronizationManager 的 unbindResource 移除 DataSource 和 ConnectionHolder 的绑定