PlatformTransactionManager
不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager
如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。
DataSourceTransactionManager
我们能在spring-boot-autoconfigure-2.7.12.jar中,能看到一个自动配置类:DataSourceTransactionManagerAutoConfiguration
@AutoConfiguration(before = TransactionAutoConfiguration.class)
@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);
}
}
}
切入new DataSourceTransactionManager(dataSource)这一行代码,继续往下看:
/**
* Create a new DataSourceTransactionManager instance.
* @param dataSource the JDBC DataSource to manage transactions for
*/
public DataSourceTransactionManager(DataSource dataSource) {
this();
setDataSource(dataSource);
afterPropertiesSet();
}
调用了org.springframework.jdbc.datasource.DataSourceTransactionManager#setDataSource
public void setDataSource(@Nullable DataSource dataSource) {
if (dataSource instanceof TransactionAwareDataSourceProxy) {
// If we got a TransactionAwareDataSourceProxy, we need to perform transactions
// for its underlying target DataSource, else data access code won't see
// properly exposed transactions (i.e. transactions for the target DataSource).
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
}
else {
this.dataSource = dataSource;
}
}
其实这个setDataSource方法,作用就是将给DataSourceTransactionManager中的dataSource属性赋值,后面所有的connection,都会依赖于这个dataSource来创建。
原始注释如下:
set the JDBC DataSource that this instance should manage transactions for.
This will typically be a locally defined DataSource,
for example an Apache Commons DBCP connection pool.
Alternatively, you can also drive transactions for a non-XA J2EE DataSource fetched from JNDI.
For an XA DataSource, use JtaTransactionManager.
The DataSource specified here should be the target DataSource to manage transactions for,
not a TransactionAwareDataSourceProxy.
Only data access code may work with TransactionAwareDataSourceProxy,
while the transaction manager needs to work on the underlying target DataSource.
If there's nevertheless a TransactionAwareDataSourceProxy passed in,
it will be unwrapped to extract its target DataSource.
The DataSource passed in here needs to return independent Connections.
The Connections may come from a pool (the typical case),
but the DataSource must not return thread-scoped / request-scoped Connections or the like.
JpaTransactionManager
如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。
在JpaBaseConfiguration
这个类中:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(JpaProperties.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
private final DataSource dataSource;
private final JpaProperties properties;
private final JtaTransactionManager jtaTransactionManager;
private ConfigurableListableBeanFactory beanFactory;
protected JpaBaseConfiguration(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
this.dataSource = dataSource;
this.properties = properties;
this.jtaTransactionManager = jtaTransactionManager.getIfAvailable();
}
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
public PlatformTransactionManager transactionManager(
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
可以看到,这里new了一个JpaTransactionManager 实例
JpaTransactionManager & JtaTransactionManager
JpaTransactionManager is a implementation of
PlatformTransactionManager for a single JPA EntityManagerFactory.
Binds a JPA EntityManager from the specified factory to the thread, potentially allowing for one thread-bound EntityManager per factory.
This JpaTransactionManager is appropriate for applications that use a single JPA EntityManagerFactory for transactional data access.
上面说完了JpaTransactionManager,下面,再来看下JtaTransactionManager:
JTA (usually through JtaTransactionManager) is necessary for accessing multiple transactional resources within the same transaction. Note that you need to configure your JPA provider accordingly in order to make it participate in JTA transactions.
JtaTransactionManager is a PlatformTransactionManager implementation for JTA, delegating to a backend JTA provider.
This is typically used to delegate to a Jakarta EE server's transaction coordinator, but may also be configured with a local JTA provider which is embedded within the application.
This transaction manager is appropriate for handling distributed transactions, i.e. transactions that span multiple resources, and for controlling transactions on application server resources (for example, JDBC DataSources available in JNDI) in general.
For a single JDBC DataSource, DataSourceTransactionManager is perfectly sufficient, and for accessing a single resource with Hibernate (including transactional cache), HibernateTransactionManager is appropriate, for example.
For typical JTA transactions (REQUIRED, SUPPORTS, MANDATORY, NEVER), a plain JtaTransactionManager definition is all you need, portable across all Jakarta EE servers.
This corresponds to the functionality of the JTA UserTransaction, for which Jakarta EE specifies a standard JNDI name ("java:comp/UserTransaction").
There is no need to configure a server-specific TransactionManager lookup for this kind of JTA usage.
Transaction suspension (REQUIRES_NEW, NOT_SUPPORTED) is just available with a JTA TransactionManager being registered.
Common TransactionManager locations are autodetected by JtaTransactionManager, provided that the "autodetectTransactionManager" flag is set to "true" (which it is by default).