一、环境
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:
- JdbcTemplate 调用 DataSourceUtils.getConnection(obtainDataSource())
- DataSourceUtils 调用 TransactionSynchronizationManager.getResource(dataSource) 获得连接,若没有连接,则调用 dataSource.getConnection(),获得连接
有事务管理器开启事务时,执行 sql:
- 开启事务时,DataSourceTransactionManager 的 getTransaction,开启事务,先调用 TransactionSynchronizationManager.getResource(obtainDataSource() 获得 ConnectionHolder,
若不存在,则使用 obtainDataSource().getConnection() 获得连接,
再调用 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()),把 ConnectionHolder 保存进 TransactionSynchronizationManager - 执行sql,JdbcTemplate 调用 DataSourceUtils.getConnection(obtainDataSource())
- DataSourceUtils 调用 TransactionSynchronizationManager.getResource(dataSource) 获得连接
4.调用 Connection 提交事务后或事务回滚后,调用 TransactionSynchronizationManager 的 unbindResource 移除 DataSource 和 ConnectionHolder 的绑定