Transaction synchronization provides callbacks and resource management infrastructure for coordinating transactional resources and performing cleanup operations at transaction boundaries. This is primarily used by framework code and resource management implementations, not typical application code.
Central delegate that manages resources and transaction synchronizations per thread. Used by resource management code to bind resources like database connections to the current transaction.
/**
* Central delegate that manages resources and transaction synchronizations per thread.
* Manages thread-bound resources and synchronization callbacks.
*/
public abstract class TransactionSynchronizationManager {
// Resource management
public static Map<Object, Object> getResourceMap();
public static boolean hasResource(Object key);
public static Object getResource(Object key);
public static void bindResource(Object key, Object value);
public static void bindSynchronizedResource(Object key, Object value);
public static Object unbindResource(Object key);
public static Object unbindResourceIfPossible(Object key);
// Synchronization management
public static boolean isSynchronizationActive();
public static void initSynchronization();
public static void registerSynchronization(TransactionSynchronization synchronization);
public static List<TransactionSynchronization> getSynchronizations();
public static void clearSynchronization();
// Transaction metadata
public static void setCurrentTransactionName(String name);
public static String getCurrentTransactionName();
public static void setCurrentTransactionReadOnly(boolean readOnly);
public static boolean isCurrentTransactionReadOnly();
public static void setCurrentTransactionIsolationLevel(Integer isolationLevel);
public static Integer getCurrentTransactionIsolationLevel();
public static void setActualTransactionActive(boolean active);
public static boolean isActualTransactionActive();
// Cleanup
public static void clear();
}Usage Examples:
import org.springframework.transaction.support.TransactionSynchronizationManager;
// Check if resource is bound
if (TransactionSynchronizationManager.hasResource(dataSource)) {
Connection conn = (Connection) TransactionSynchronizationManager.getResource(dataSource);
// Use connection
}
// Bind resource to transaction
Connection conn = dataSource.getConnection();
TransactionSynchronizationManager.bindResource(dataSource, conn);
// Register synchronization callback
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// Cleanup or notification after commit
cacheManager.invalidate();
}
}
);
}
// Check transaction metadata
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
// Use read-only optimization
}Callback interface for resource cleanup and transaction event notification. Implementations can register with TransactionSynchronizationManager to receive callbacks at various transaction phases.
/**
* Callback interface for resource cleanup and synchronization at transaction completion.
* All methods have default implementations for convenience.
*/
public interface TransactionSynchronization extends Ordered, Flushable {
/** Status for committed transactions */
int STATUS_COMMITTED = 0;
/** Status for rolled back transactions */
int STATUS_ROLLED_BACK = 1;
/** Status when completion status is unknown */
int STATUS_UNKNOWN = 2;
/**
* Return the execution order (default is Ordered.LOWEST_PRECEDENCE).
*/
default int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
/**
* Suspend this synchronization. Called before the transaction is suspended.
*/
default void suspend() {
}
/**
* Resume this synchronization. Called after the transaction is resumed.
*/
default void resume() {
}
/**
* Flush the underlying session to the datastore, if applicable.
*/
@Override
default void flush() {
}
/**
* Invoked when a savepoint is created.
*/
default void savepoint(Object savepoint) {
}
/**
* Invoked when rolled back to a savepoint.
*/
default void savepointRollback(Object savepoint) {
}
/**
* Invoked before transaction commit (before "beforeCompletion").
* @param readOnly whether transaction is read-only
*/
default void beforeCommit(boolean readOnly) {
}
/**
* Invoked before transaction commit/rollback.
*/
default void beforeCompletion() {
}
/**
* Invoked after transaction commit.
*/
default void afterCommit() {
}
/**
* Invoked after transaction commit/rollback.
* @param status completion status (STATUS_COMMITTED, STATUS_ROLLED_BACK, STATUS_UNKNOWN)
*/
default void afterCompletion(int status) {
}
}Usage Examples:
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
// Custom synchronization for cache invalidation
public class CacheInvalidationSynchronization implements TransactionSynchronization {
private final CacheManager cacheManager;
private final String cacheKey;
public CacheInvalidationSynchronization(CacheManager cacheManager, String cacheKey) {
this.cacheManager = cacheManager;
this.cacheKey = cacheKey;
}
@Override
public void afterCommit() {
cacheManager.evict(cacheKey);
}
@Override
public void afterCompletion(int status) {
if (status == STATUS_ROLLED_BACK) {
// Log rollback for monitoring
logger.warn("Transaction rolled back for cache key: {}", cacheKey);
}
}
}
// Register synchronization
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new CacheInvalidationSynchronization(cacheManager, "users:123")
);
}Abstract adapter class for TransactionSynchronization interface. Provides empty default implementations for all methods, making it convenient to extend when you only need to override specific callbacks.
/**
* Abstract adapter class for TransactionSynchronization interface.
* Deprecated as of Spring Framework 7.0 - use TransactionSynchronization default methods directly.
*/
@Deprecated(since = "7.0", forRemoval = true)
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public void suspend() {
}
@Override
public void resume() {
}
@Override
public void flush() {
}
@Override
public void beforeCommit(boolean readOnly) {
}
@Override
public void beforeCompletion() {
}
@Override
public void afterCommit() {
}
@Override
public void afterCompletion(int status) {
}
}Note: As of Spring Framework 7.0, this class is deprecated. Use TransactionSynchronization interface directly as it now provides default method implementations.
Utility methods for triggering specific TransactionSynchronization callbacks and for resource unwrapping.
/**
* Utility methods for triggering TransactionSynchronization callbacks.
*/
public abstract class TransactionSynchronizationUtils {
/**
* Check whether the given resource transaction managers refer to the same underlying target.
*/
public static boolean sameResourceFactory(
Object resourceFactory1,
Object resourceFactory2
);
/**
* Unwrap the given resource if necessary (removes proxies).
*/
public static Object unwrapResourceIfNecessary(Object resource);
/**
* Trigger flush callbacks on all currently registered synchronizations.
*/
public static void triggerFlush();
/**
* Trigger beforeCommit callbacks on all currently registered synchronizations.
*/
public static void triggerBeforeCommit(boolean readOnly);
/**
* Trigger beforeCompletion callbacks on all currently registered synchronizations.
*/
public static void triggerBeforeCompletion();
/**
* Trigger afterCommit callbacks on all currently registered synchronizations.
*/
public static void triggerAfterCommit();
/**
* Trigger afterCompletion callbacks on all currently registered synchronizations.
*/
public static void triggerAfterCompletion(int completionStatus);
/**
* Invoke afterCommit callbacks, properly handling exceptions.
*/
public static void invokeAfterCommit(List<TransactionSynchronization> synchronizations);
/**
* Invoke afterCompletion callbacks, properly handling exceptions.
*/
public static void invokeAfterCompletion(
List<TransactionSynchronization> synchronizations,
int completionStatus
);
}Interface for resource holders that can be bound to threads via TransactionSynchronizationManager. Typically implemented by connection or session holders.
/**
* Interface for resource holders that manage transactional resources.
*/
public interface ResourceHolder {
/**
* Reset the transactional state of this holder.
*/
void reset();
/**
* Notify this holder that it has been unbound from transaction synchronization.
*/
void unbound();
/**
* Determine whether this holder is considered 'void' (empty/released).
*/
boolean isVoid();
}Abstract base class for resource holders. Provides common functionality for timeout management and rollback tracking.
/**
* Abstract base class for resource holders.
* Provides timeout management and rollback tracking.
*/
public abstract class ResourceHolderSupport implements ResourceHolder {
/**
* Mark the holder as synchronized with transaction.
*/
public void setSynchronizedWithTransaction(boolean synchronizedWithTransaction);
/**
* Return whether this holder is synchronized with a transaction.
*/
public boolean isSynchronizedWithTransaction();
/**
* Mark this holder as rollback-only.
*/
public void setRollbackOnly();
/**
* Return whether this holder is marked as rollback-only.
*/
public boolean isRollbackOnly();
/**
* Set the timeout for this holder in seconds.
*/
public void setTimeoutInSeconds(int seconds);
/**
* Set the timeout for this holder in milliseconds.
*/
public void setTimeoutInMillis(long millis);
/**
* Return whether this holder has a timeout.
*/
public boolean hasTimeout();
/**
* Return the time to live for this holder in seconds.
*/
public long getTimeToLiveInSeconds();
/**
* Return the time to live for this holder in milliseconds.
*/
public long getTimeToLiveInMillis();
/**
* Reset the transactional state.
*/
@Override
public void reset();
/**
* Notify that the holder has been unbound from transaction.
*/
@Override
public void unbound();
/**
* Return whether this holder is void/empty.
*/
@Override
public boolean isVoid();
}Usage Example:
import org.springframework.transaction.support.ResourceHolderSupport;
public class ConnectionHolder extends ResourceHolderSupport {
private Connection connection;
public ConnectionHolder(Connection connection) {
this.connection = connection;
}
public Connection getConnection() {
return this.connection;
}
@Override
public void reset() {
super.reset();
// Reset connection state if needed
}
@Override
public boolean isVoid() {
return (this.connection == null);
}
public void released() {
this.connection = null;
}
}Abstract adapter for registering a ResourceHolder with transaction synchronization. Automatically unbinds the resource at transaction completion.
/**
* Abstract adapter for registering ResourceHolders with transaction synchronization.
* Automatically unbinds resource after transaction completion.
*/
public abstract class ResourceHolderSynchronization<H extends ResourceHolder, K>
implements TransactionSynchronization {
private final H resourceHolder;
private final K resourceKey;
private volatile boolean holderActive = true;
/**
* Create a new ResourceHolderSynchronization for the given holder.
* @param resourceHolder the ResourceHolder to manage
* @param resourceKey the key to unbind the ResourceHolder for
*/
public ResourceHolderSynchronization(H resourceHolder, K resourceKey) {
this.resourceHolder = resourceHolder;
this.resourceKey = resourceKey;
}
@Override
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.resourceKey);
}
}
@Override
public void resume() {
if (this.holderActive) {
TransactionSynchronizationManager.bindResource(this.resourceKey, this.resourceHolder);
}
}
@Override
public void beforeCompletion() {
if (shouldUnbindAtCompletion()) {
TransactionSynchronizationManager.unbindResource(this.resourceKey);
this.holderActive = false;
releaseResource(this.resourceHolder, this.resourceKey);
}
}
@Override
public void afterCompletion(int status) {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResourceIfPossible(this.resourceKey);
this.holderActive = false;
releaseResource(this.resourceHolder, this.resourceKey);
}
}
/**
* Return whether to unbind at completion (default is true).
*/
protected boolean shouldUnbindAtCompletion() {
return true;
}
/**
* Release the given resource after transaction completion.
* @param resourceHolder the ResourceHolder to process
* @param resourceKey the key that the ResourceHolder was bound for
*/
protected abstract void releaseResource(H resourceHolder, K resourceKey);
}import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.ResourceHolderSupport;
public class CustomResourceManager {
private final ResourceFactory resourceFactory;
public Resource getResource() {
// Check if resource is already bound
ResourceHolder holder = (ResourceHolder)
TransactionSynchronizationManager.getResource(resourceFactory);
if (holder != null && !holder.isVoid()) {
return holder.getResource();
}
// Create new resource
Resource resource = resourceFactory.createResource();
// Bind to transaction if synchronization is active
if (TransactionSynchronizationManager.isSynchronizationActive()) {
ResourceHolder newHolder = new ResourceHolder(resource);
TransactionSynchronizationManager.bindResource(resourceFactory, newHolder);
// Register for cleanup
TransactionSynchronizationManager.registerSynchronization(
new ResourceHolderSynchronization<>(newHolder, resourceFactory) {
@Override
protected void releaseResource(ResourceHolder holder, Object key) {
holder.getResource().close();
}
}
);
}
return resource;
}
}import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class TransactionalCacheManager {
private final Cache cache;
public void put(String key, Object value) {
// Only update cache after successful commit
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
cache.put(key, value);
}
@Override
public void afterCompletion(int status) {
if (status == STATUS_ROLLED_BACK) {
// Ensure cache is not polluted on rollback
cache.evict(key);
}
}
}
);
} else {
// No transaction, update immediately
cache.put(key, value);
}
}
}import org.springframework.transaction.support.TransactionSynchronization;
public class CleanupCoordinator implements TransactionSynchronization {
private final List<Closeable> resources = new ArrayList<>();
public void registerResource(Closeable resource) {
resources.add(resource);
}
@Override
public void beforeCompletion() {
// Flush all resources before commit
for (Closeable resource : resources) {
if (resource instanceof Flushable flushable) {
try {
flushable.flush();
} catch (IOException e) {
logger.warn("Failed to flush resource", e);
}
}
}
}
@Override
public void afterCompletion(int status) {
// Close all resources after transaction completion
for (Closeable resource : resources) {
try {
resource.close();
} catch (IOException e) {
logger.warn("Failed to close resource", e);
}
}
resources.clear();
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE; // Close last
}
}