Spring事务02事务管理器3DataSourceTransactionManager
挑几个常见的实现类,Spring 事务管理重要的是 DataSourceTransactionManager 。
DataSourceTransactionManager 中方法如下:
1 类解释
{@link org.springframework.transaction.PlatformTransactionManager}implementation for a single JDBC {@link javax.sql.DataSource}.
This class is capable of working in any environment with any JDBC driver,
as long as the setup uses a {@code javax.sql.DataSource} as its {@code Connection} factory mechanism.
Binds a JDBC Connection from the specified DataSource to the current thread,
potentially allowing for one thread-bound Connection per DataSource.
<p>Note: The DataSource that this transaction manager operates on 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.
This transaction manager will associate Connections with thread-bound transactions itself,
according to the specified propagation behavior.
It assumes that a separate, independent Connection can be obtained even during an ongoing transaction.
<p>Application code is required to retrieve the JDBC Connection via {@link DataSourceUtils#getConnection(DataSource)} instead of a standard Java EE-style {@link DataSource#getConnection()} call.
Spring classes such as {@link org.springframework.jdbc.core.JdbcTemplate} use this strategy implicitly.
If not used in combination with this transaction manager,
the {@link DataSourceUtils} lookup strategy behaves exactly like the native DataSource lookup;
it can thus be used in a portable fashion.
<p>Alternatively, you can allow application code to work with the standard Java EE-style lookup pattern {@link DataSource#getConnection()},
for example for legacy code that is not aware of Spring at all.
In that case, define a {@link TransactionAwareDataSourceProxy} for your target DataSource,
and pass that proxy DataSource to your DAOs,
which will automatically participate in Spring-managed transactions when accessing it.
<p>Supports custom isolation levels, and timeouts which get applied as appropriate JDBC statement timeouts.
To support the latter, application code must either use {@link org.springframework.jdbc.core.JdbcTemplate},
call {@link DataSourceUtils#applyTransactionTimeout} for each created JDBC Statement,
or go through a {@link TransactionAwareDataSourceProxy} which will create timeout-aware JDBC Connections and Statements automatically.
<p>Consider defining a {@link LazyConnectionDataSourceProxy} for your target DataSource,
pointing both this transaction manager and your DAOs to it.
This will lead to optimized handling of "empty" transactions,
i.e. of transactions without any JDBC statements executed.
A LazyConnectionDataSourceProxy will not fetch an actual JDBC Connection from the target DataSource until a Statement gets executed,
lazily applying the specified transaction settings to the target Connection.
<p>This transaction manager supports nested transactions via the JDBC 3.0 {@link java.sql.Savepoint} mechanism.
The {@link #setNestedTransactionAllowed "nestedTransactionAllowed"} flag defaults to "true",
since nested transactions will work without restrictions on JDBC drivers that support savepoints (such as the Oracle JDBC driver).
<p>This transaction manager can be used as a replacement for the {@link org.springframework.transaction.jta.JtaTransactionManager} in the single resource case,
as it does not require a container that supports JTA,
typically in combination with a locally defined JDBC DataSource (e.g. an Apache Commons DBCP connection pool).
Switching between this local strategy and a JTA environment is just a matter of configuration!
<p>As of 4.3.4, this transaction manager triggers flush callbacks on registered transaction synchronizations (if synchronization is generally active),
assuming resources operating on the underlying JDBC {@code Connection}.
This allows for setup analogous to {@code JtaTransactionManager},
in particular with respect to lazily registered ORM resources (e.g. a Hibernate {@code Session}).
-------------翻译-------------
{@link org.springframework.transaction.PlatformTransactionManager}
单个JDBC {@link javax.sql.DataSource}的实现。
这个类可以在任何环境下使用任何JDBC驱动程序,
只要设置使用{@code javax.sql。将DataSource}作为其{@code连接}工厂机制。
将指定数据源的JDBC连接绑定到当前线程,
可能允许每个数据源有一个线程绑定连接。
注意:这个事务管理器操作的数据源需要返回独立的连接。
连接可能来自池(典型情况),但数据源不能返回线程范围/请求范围的连接或类似的连接。
这个事务管理器将把连接与线程绑定的事务本身关联起来,
根据指定的传播行为。
它假设即使在正在进行的事务中也可以获得独立的连接。
<p>应用程序代码需要通过{@link DataSourceUtils#getConnection(DataSource)}而不是标准的Java EE-style {@link DataSource#getConnection()}调用来检索JDBC连接。
像{@link org.springframework.jdb .core这样的Spring类。JdbcTemplate}隐式地使用这个策略。
如果不与此事务管理器一起使用,
{@link DataSourceUtils}查找策略的行为与原生数据源查找完全相同;
因此,它可以以一种便携的方式使用。
<p>或者,您可以允许应用程序代码使用标准的Java ee风格的查找模式{@link DataSource#getConnection()},
例如,对于根本不知道Spring的遗留代码。
在这种情况下,为你的目标数据源定义一个{@link TransactionAwareDataSourceProxy},
然后把代理数据源传给你的dao,
当访问spring管理的事务时,它将自动参与其中。
<p>支持自定义隔离级别,以及作为适当的JDBC语句超时应用的超时。
要支持后者,应用程序代码必须使用{@link org.springframework.jdbc.core.JdbcTemplate},
为每个创建的JDBC语句调用{@link DataSourceUtils#applyTransactionTimeout},
或者访问{@link TransactionAwareDataSourceProxy},它将自动创建支持超时的JDBC连接和语句。
<p>考虑为你的目标数据源定义一个{@link LazyConnectionDataSourceProxy},
将这个事务管理器和您的dao指向它。
这将导致对“空”事务的优化处理,
即不执行任何JDBC语句的事务。
在执行语句之前,LazyConnectionDataSourceProxy不会从目标数据源获取实际的JDBC连接,
将指定的事务设置惰性地应用于目标连接。
这个事务管理器通过JDBC 3.0 {@link java.sql支持嵌套事务。保存点}机制。
{@link #setNestedTransactionAllowed "nestedTransactionAllowed"}标志默认为"true",
因为嵌套事务在支持保存点(如Oracle JDBC驱动程序)的JDBC驱动程序上没有限制。
<p>这个事务管理器可以用来代替{@link org.springframework.transaction.jta。在单一资源的情况下,
因为它不需要一个支持JTA的容器,
通常与本地定义的JDBC数据源相结合(例如,Apache Commons DBCP连接池)。
在本地策略和JTA环境之间切换只是配置问题!
<p>从4.3.4开始,这个事务管理器在已注册的事务同步上触发刷新回调(如果同步通常是活动的),
假设资源在底层JDBC {@code连接}上运行。
这允许类似{@code JtaTransactionManager}的设置,
特别是惰性注册的ORM资源(例如Hibernate {@code Session})。
2 方法解释
2.1 doGetTransaction()
@Overrideprotected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
2.2 doBegin()
/** * This implementation sets the isolation level but ignores the timeout.
* 此实现设置隔离级别,但忽略超时。
*/
@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();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don"t want to do it unnecessarily (for example if we"ve explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
2.3 doCommit()
@Overrideprotected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
2.4 doRollback()
@Overrideprotected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
2.5 isExistingTransaction()
@Overrideprotected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
2.6 doSuspend()
@Overrideprotected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
2.7 doResume()
@Overrideprotected void doResume(@Nullable Object transaction, Object suspendedResources) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
2.8 doSetRollbackOnly()
@Overrideprotected void doSetRollbackOnly(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
"] rollback-only");
}
txObject.setRollbackOnly();
}
2.9 doCleanupAfterCompletion()
事务完成后清理资源。
在执行{@code doCommit}和{@code doRollback}之后,对任何结果调用。
@Overrideprotected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// Remove the connection holder from the thread, if exposed.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// Reset connection.
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
3 其他方法
package org.springframework.jdbc.datasource;import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionSynchronizationUtils;
import org.springframework.util.Assert;
/**
* @see #setNestedTransactionAllowed
* @see java.sql.Savepoint
* @see DataSourceUtils#getConnection(javax.sql.DataSource)
* @see DataSourceUtils#applyTransactionTimeout
* @see DataSourceUtils#releaseConnection
* @see TransactionAwareDataSourceProxy
* @see LazyConnectionDataSourceProxy
* @see org.springframework.jdbc.core.JdbcTemplate
*/
@SuppressWarnings("serial")
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Nullable
private DataSource dataSource;
private boolean enforceReadOnly = false;
/**
* 创建一个新的DataSourceTransactionManager实例。
* 必须设置一个数据源才能使用它。
*
* @see #setDataSource
*/
public DataSourceTransactionManager() {
setNestedTransactionAllowed(true);
}
/**
* 创建一个新的DataSourceTransactionManager实例
* @param dataSource 用于管理事务的JDBC数据源
*/
public DataSourceTransactionManager(DataSource dataSource) {
this();
setDataSource(dataSource);
afterPropertiesSet();
}
/**
* 设置此实例应该为其管理事务的JDBC数据源。
*
* 这通常是一个本地定义的数据源,例如一个apache Commons DBCP连接池。
* 另外,您还可以驱动从JNDI获取的非xa J2EE数据源的事务。
* 对于XA数据源,使用JtaTransactionManager。
*
* 这里指定的数据源应该是管理事务的目标数据源,而不是TransactionAwareDataSourceProxy。
* 只有数据访问代码可以使用TransactionAwareDataSourceProxy,
* 而事务管理器需要处理底层目标数据源。
* 如果传入了一个TransactionAwareDataSourceProxy,
* 它将被打开以提取其目标数据源。
*
* 这里传递的数据源需要返回独立的连接。
* 连接可能来自池(典型情况),但数据源不能返回线程范围/请求范围的连接或类似的连接。
*
* @see TransactionAwareDataSourceProxy
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
public void setDataSource(@Nullable DataSource dataSource) {
if (dataSource instanceof TransactionAwareDataSourceProxy) {
// 如果我们有一个TransactionAwareDataSourceProxy,
// 我们需要为它的底层目标数据源执行事务,
// 否则,数据访问代码将无法看到正确公开的事务(即目标数据源的事务)。
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
}
else {
this.dataSource = dataSource;
}
}
/**
* Return the JDBC DataSource that this instance manages transactions for.
* 返回此管理事务的JDBC数据源的实例。
*/
@Nullable
public DataSource getDataSource() {
return this.dataSource;
}
/**
* Obtain the DataSource for actual use.
* 获取实际使用的数据源。
*
* @return the DataSource (never {@code null})
* @throws IllegalStateException in case of no DataSource set
* @since 5.0
*/
protected DataSource obtainDataSource() {
DataSource dataSource = getDataSource();
Assert.state(dataSource != null, "No DataSource set");
return dataSource;
}
/**
* 指定是否强制事务的只读性质(如{@link TransactionDefinition#isReadOnly()}
* 通过事务连接上的显式语句表示:“设置事务只读”,这是Oracle、MySQL和Postgres所理解的。
*
* 确切的处理,包括连接上执行的任何SQL语句,
* 可以通过{@link #prepareTransactionalConnection}定制。
*
* 这种只读处理模式超出了默认应用Spring的{@link Connection#setReadOnly}提示。
* 与标准的JDBC提示不同,“SET TRANSACTION READ ONLY”强制了一种隔离级的连接模式,其中数据操作语句是严格禁止的。
* 另外,在Oracle上,这种只读模式为整个事务提供了读一致性。
*
* 注意,以前的Oracle JDBC驱动程序(9i, 10g)用于强制执行这种只读模式,即使对于{@code Connection.setReadOnly(true}也是如此。
* 但是,对于最近的驱动程序,这种强大的强制需要明确地应用,例如通过这个标志。
*
* @since 4.3.7
* @see #prepareTransactionalConnection
*/
public void setEnforceReadOnly(boolean enforceReadOnly) {
this.enforceReadOnly = enforceReadOnly;
}
/**
* Return whether to enforce the read-only nature of a transaction
* through an explicit statement on the transactional connection.
*
* 返回是否通过事务连接上的显式语句强制事务的只读性质。
*
* @since 4.3.7
* @see #setEnforceReadOnly
*/
public boolean isEnforceReadOnly() {
return this.enforceReadOnly;
}
/**
* afterPropertiesSet() 是 InitializingBean 接口中的方法
*/
@Override
public void afterPropertiesSet() {
if (getDataSource() == null) {
throw new IllegalArgumentException("Property "dataSource" is required");
}
}
@Override
public Object getResourceFactory() {
return obtainDataSource();
}
/**
* 在事务开始后立即准备事务{@code连接}。
*
* 如果{@link #setEnforceReadOnly "enforceReadOnly"标志设置为{@code true},则默认实现执行“SET TRANSACTION READ ONLY”语句
* 事务定义表示只读事务。
*
* “设置事务只读”被Oracle、MySQL和Postgres理解,也可以用于其他数据库。
* 如果您想采用这种处理方法,请相应地重写此方法。
*
* @param con the transactional JDBC Connection
* @param definition the current transaction definition
* @throws SQLException if thrown by JDBC API
* @since 4.3.7
* @see #setEnforceReadOnly
*/
protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition)
throws SQLException {
if (isEnforceReadOnly() && definition.isReadOnly()) {
Statement stmt = con.createStatement();
try {
stmt.executeUpdate("SET TRANSACTION READ ONLY");
}
finally {
stmt.close();
}
}
}
/**
* 数据源事务对象,表示一个ConnectionHolder。
* 被DataSourceTransactionManager用作事务对象。
*/
private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport {
private boolean newConnectionHolder;
private boolean mustRestoreAutoCommit;
public void setConnectionHolder(@Nullable ConnectionHolder connectionHolder, boolean newConnectionHolder) {
super.setConnectionHolder(connectionHolder);
this.newConnectionHolder = newConnectionHolder;
}
public boolean isNewConnectionHolder() {
return this.newConnectionHolder;
}
public void setMustRestoreAutoCommit(boolean mustRestoreAutoCommit) {
this.mustRestoreAutoCommit = mustRestoreAutoCommit;
}
public boolean isMustRestoreAutoCommit() {
return this.mustRestoreAutoCommit;
}
public void setRollbackOnly() {
getConnectionHolder().setRollbackOnly();
}
@Override
public boolean isRollbackOnly() {
return getConnectionHolder().isRollbackOnly();
}
@Override
public void flush() {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationUtils.triggerFlush();
}
}
}
}
以上是 Spring事务02事务管理器3DataSourceTransactionManager 的全部内容, 来源链接: utcz.com/z/513321.html