简介
TransactionSynchronizationManager是Spring框架中用于管理事务同步的核心类,它提供了一系列静态方法来处理与事务同步相关的各种操作。以下是一些TransactionSynchronizationManager中常用的方法及其介绍:
注册事务同步器:
- registerSynchronization(TransactionSynchronization synchronization): 此方法用于注册一个TransactionSynchronization对象,该对象包含了在事务的不同阶段(如提交、回滚、完成等)需要执行的逻辑。注册后,当事务到达相应的阶段时,这些逻辑会被自动触发。
获取事务信息: - isActualTransactionActive(): 返回一个布尔值,表示当前是否有一个实际的活动事务。
- getCurrentTransactionName(): 获取当前事务的名称。
- getCurrentTransactionIsolationLevel(): 获取当前事务的隔离级别。
- isCurrentTransactionReadOnly(): 判断当前事务是否只读。
资源绑定与检索: - bindResource(Object key, Object value): 将一个资源(通常是一个对象)绑定到当前事务的上下文中,使用指定的键进行标识。
- unbindResource(Object key): 从当前事务的上下文中解绑一个之前绑定的资源。
- getResource(Object key): 根据给定的键检索之前绑定到当前事务上下文中的资源。
获取已注册的事务同步器: - getSynchronizations(): 返回一个不可修改的列表,其中包含当前线程已注册的所有事务同步器。
事务同步事件触发:
当事务到达某个阶段(如提交、回滚)时,TransactionSynchronizationManager会触发相应的事务同步事件。已注册的事务同步器会响应这些事件并执行相应的操作。
需要注意的是,直接使用TransactionSynchronizationManager通常是在进行高级事务管理或自定义同步行为时。在大多数情况下,Spring的声明式事务管理(通过@Transactional注解)和编程式事务管理(通过PlatformTransactionManager接口)已经提供了足够的功能来满足常见的需求。直接操作TransactionSynchronizationManager需要对Spring的事务管理有深入的理解,并要小心处理以避免潜在的并发问题或事务泄露等错误。
源码
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
//这里是用来存放ConnectHolder
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
//存放事务同步器
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
//存放当前事务的name
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
//当前事务只读状态
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
//当前事务的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
//当前事务是否被正在使用
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
//-------------------------------------------------------------------------
// Management of transaction-associated resource handles
//-------------------------------------------------------------------------
/**
* Return all resources that are bound to the current thread.
* <p>Mainly for debugging purposes. Resource managers should always invoke
* {@code hasResource} for a specific resource key that they are interested in.
* @return a Map with resource keys (usually the resource factory) and resource
* values (usually the active resource object), or an empty Map if there are
* currently no resources bound
* @see #hasResource
*/
public static Map<Object, Object> getResourceMap() {
Map<Object, Object> map = resources.get();
return (map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap());
}
/**
* Check if there is a resource for the given key bound to the current thread.
* @param key the key to check (usually the resource factory)
* @return if there is a value bound to the current thread
* @see ResourceTransactionManager#getResourceFactory()
*/
public static boolean hasResource(Object key) {
//判断当前资源是否存在
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
return (value != null);
}
/**
* Retrieve a resource for the given key that is bound to the current thread.
* @param key the key to check (usually the resource factory)
* @return a value bound to the current thread (usually the active
* resource object), or {@code null} if none
* @see ResourceTransactionManager#getResourceFactory()
*/
@Nullable
public static Object getResource(Object key) {
//获取包装key
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
//获取ConnectHolder
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
/**
* Actually check the value of the resource that is bound for the given key.
*/
@Nullable
private static Object doGetResource(Object actualKey) {
//从ThreadLocal中获取
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
//根据key查找
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
/**
* Bind the given resource for the given key to the current thread.
* @param key the key to bind the value to (usually the resource factory)
* @param value the value to bind (usually the active resource object)
* @throws IllegalStateException if there is already a value bound to the thread
* @see ResourceTransactionManager#getResourceFactory()
* 将资源绑定到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 [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
Thread.currentThread().getName() + "]");
}
}
/**
* Unbind a resource for the given key from the current thread.
* @param key the key to unbind (usually the resource factory)
* @return the previously bound value (usually the active resource object)
* @throws IllegalStateException if there is no value bound to the thread
* @see ResourceTransactionManager#getResourceFactory()
* 解绑资源
*/
public static Object unbindResource(Object key) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doUnbindResource(actualKey);
if (value == null) {
throw new IllegalStateException(
"No value for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
return value;
}
/**
* Unbind a resource for the given key from the current thread.
* @param key the key to unbind (usually the resource factory)
* @return the previously bound value, or {@code null} if none bound
*/
@Nullable
public static Object unbindResourceIfPossible(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
return doUnbindResource(actualKey);
}
/**
* Actually remove the value of the resource that is bound for the given key.
* 解绑
*/
@Nullable
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
// Transparently suppress a ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
value = null;
}
if (value != null && logger.isTraceEnabled()) {
logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
//-------------------------------------------------------------------------
// Management of transaction synchronizations
//-------------------------------------------------------------------------
/**
* Return if transaction synchronization is active for the current thread.
* Can be called before register to avoid unnecessary instance creation.
* @see #registerSynchronization
* 事务同步器是否还存活
*/
public static boolean isSynchronizationActive() {
return (synchronizations.get() != null);
}
/**
* Activate transaction synchronization for the current thread.
* Called by a transaction manager on transaction begin.
* @throws IllegalStateException if synchronization is already active
*/
public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
}
logger.trace("Initializing transaction synchronization");
synchronizations.set(new LinkedHashSet<>());
}
/**
* Register a new transaction synchronization for the current thread.
* Typically called by resource management code.
* <p>Note that synchronizations can implement the
* {@link org.springframework.core.Ordered} interface.
* They will be executed in an order according to their order value (if any).
* @param synchronization the synchronization object to register
* @throws IllegalStateException if transaction synchronization is not active
* @see org.springframework.core.Ordered
* 用于注册一个TransactionSynchronization对象,该对象包含了在事务的不同阶段(如提交、回滚、完成等)需要执行的逻辑。
* 注册后,当事务到达相应的阶段时,这些逻辑会被自动触发。
*/
public static void registerSynchronization(TransactionSynchronization synchronization)
throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
Set<TransactionSynchronization> synchs = synchronizations.get();
if (synchs == null) {
throw new IllegalStateException("Transaction synchronization is not active");
}
synchs.add(synchronization);
}
/**
* Return an unmodifiable snapshot list of all registered synchronizations
* for the current thread.
* @return unmodifiable List of TransactionSynchronization instances
* @throws IllegalStateException if synchronization is not active
* @see TransactionSynchronization
* 返回一个不可修改的列表,其中包含当前线程已注册的所有事务同步器。
*/
public static List<TransactionSynchronization> getSynchronizations() throws IllegalStateException {
Set<TransactionSynchronization> synchs = synchronizations.get();
if (synchs == null) {
throw new IllegalStateException("Transaction synchronization is not active");
}
// Return unmodifiable snapshot, to avoid ConcurrentModificationExceptions
// while iterating and invoking synchronization callbacks that in turn
// might register further synchronizations.
if (synchs.isEmpty()) {
return Collections.emptyList();
}
else {
// Sort lazily here, not in registerSynchronization.
List<TransactionSynchronization> sortedSynchs = new ArrayList<>(synchs);
AnnotationAwareOrderComparator.sort(sortedSynchs);
return Collections.unmodifiableList(sortedSynchs);
}
}
/**
* Deactivate transaction synchronization for the current thread.
* Called by the transaction manager on transaction cleanup.
* @throws IllegalStateException if synchronization is not active
* 对于当前线程停用事务同步。
该方法由事务管理器在事务清理时调用。
这句话描述了TransactionSynchronizationManager中的一个操作,即在事务清理时,由事务管理器调用以停用当前线程的事务同步。
这通常发生在事务提交或回滚之后,以确保线程不会继续参与已结束的事务。
停用事务同步意味着清除与事务同步相关的所有状态和资源,以便线程能够安全地参与新的事务。
*/
public static void clearSynchronization() throws IllegalStateException {
if (!isSynchronizationActive()) {
throw new IllegalStateException("Cannot deactivate transaction synchronization - not active");
}
logger.trace("Clearing transaction synchronization");
synchronizations.remove();
}
//-------------------------------------------------------------------------
// Exposure of transaction characteristics
//-------------------------------------------------------------------------
/**
* Expose the name of the current transaction, if any.
* Called by the transaction manager on transaction begin and on cleanup.
* @param name the name of the transaction, or {@code null} to reset it
* @see org.springframework.transaction.TransactionDefinition#getName()
*/
public static void setCurrentTransactionName(@Nullable String name) {
currentTransactionName.set(name);
}
/**
* Return the name of the current transaction, or {@code null} if none set.
* To be called by resource management code for optimizations per use case,
* for example to optimize fetch strategies for specific named transactions.
* @see org.springframework.transaction.TransactionDefinition#getName()
* 获取当前事务的名称
*/
@Nullable
public static String getCurrentTransactionName() {
return currentTransactionName.get();
}
/**
* Expose a read-only flag for the current transaction.
* Called by the transaction manager on transaction begin and on cleanup.
* @param readOnly {@code true} to mark the current transaction
* as read-only; {@code false} to reset such a read-only marker
* @see org.springframework.transaction.TransactionDefinition#isReadOnly()
*/
public static void setCurrentTransactionReadOnly(boolean readOnly) {
currentTransactionReadOnly.set(readOnly ? Boolean.TRUE : null);
}
/**
* Return whether the current transaction is marked as read-only.
* To be called by resource management code when preparing a newly
* created resource (for example, a Hibernate Session).
* <p>Note that transaction synchronizations receive the read-only flag
* as argument for the {@code beforeCommit} callback, to be able
* to suppress change detection on commit. The present method is meant
* to be used for earlier read-only checks, for example to set the
* flush mode of a Hibernate Session to "FlushMode.MANUAL" upfront.
* @see org.springframework.transaction.TransactionDefinition#isReadOnly()
* @see TransactionSynchronization#beforeCommit(boolean)
* 判断当前事务是否只读
*/
public static boolean isCurrentTransactionReadOnly() {
return (currentTransactionReadOnly.get() != null);
}
/**
* Expose an isolation level for the current transaction.
* Called by the transaction manager on transaction begin and on cleanup.
* @param isolationLevel the isolation level to expose, according to the
* JDBC Connection constants (equivalent to the corresponding Spring
* TransactionDefinition constants), or {@code null} to reset it
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
* @see java.sql.Connection#TRANSACTION_SERIALIZABLE
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_UNCOMMITTED
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_COMMITTED
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_REPEATABLE_READ
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_SERIALIZABLE
* @see org.springframework.transaction.TransactionDefinition#getIsolationLevel()
*/
public static void setCurrentTransactionIsolationLevel(@Nullable Integer isolationLevel) {
currentTransactionIsolationLevel.set(isolationLevel);
}
/**
* Return the isolation level for the current transaction, if any.
* To be called by resource management code when preparing a newly
* created resource (for example, a JDBC Connection).
* @return the currently exposed isolation level, according to the
* JDBC Connection constants (equivalent to the corresponding Spring
* TransactionDefinition constants), or {@code null} if none
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
* @see java.sql.Connection#TRANSACTION_SERIALIZABLE
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_UNCOMMITTED
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_COMMITTED
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_REPEATABLE_READ
* @see org.springframework.transaction.TransactionDefinition#ISOLATION_SERIALIZABLE
* @see org.springframework.transaction.TransactionDefinition#getIsolationLevel()
* 获取当前事务的隔离级别
*/
@Nullable
public static Integer getCurrentTransactionIsolationLevel() {
return currentTransactionIsolationLevel.get();
}
/**
* Expose whether there currently is an actual transaction active.
* Called by the transaction manager on transaction begin and on cleanup.
* @param active {@code true} to mark the current thread as being associated
* with an actual transaction; {@code false} to reset that marker
*/
public static void setActualTransactionActive(boolean active) {
actualTransactionActive.set(active ? Boolean.TRUE : null);
}
/**
* Return whether there currently is an actual transaction active.
* This indicates whether the current thread is associated with an actual
* transaction rather than just with active transaction synchronization.
* <p>To be called by resource management code that wants to discriminate
* between active transaction synchronization (with or without backing
* resource transaction; also on PROPAGATION_SUPPORTS) and an actual
* transaction being active (with backing resource transaction;
* on PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, etc).
* @see #isSynchronizationActive()
* 表示当前是否有一个实际的活动事务。
*/
public static boolean isActualTransactionActive() {
return (actualTransactionActive.get() != null);
}
/**
* Clear the entire transaction synchronization state for the current thread:
* registered synchronizations as well as the various transaction characteristics.
* @see #clearSynchronization()
* @see #setCurrentTransactionName
* @see #setCurrentTransactionReadOnly
* @see #setCurrentTransactionIsolationLevel
* @see #setActualTransactionActive
* 清除当前线程的整个事务同步状态:包括已注册的事务同步器以及各种事务特性。
这句话是在描述TransactionSynchronizationManager的一个功能,即清除当前线程中的所有事务同步状态和特性。
这通常发生在事务结束时,以确保线程在下次参与新事务时处于干净的状态。
*/
public static void clear() {
synchronizations.remove();
currentTransactionName.remove();
currentTransactionReadOnly.remove();
currentTransactionIsolationLevel.remove();
actualTransactionActive.remove();
}
}