or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aop-interceptors.mddao-support.mddeclarative-transactions.mdexception-hierarchy.mdindex.mdjca-support.mdprogrammatic-transactions.mdreactive-transactions.mdtransaction-events.mdtransaction-managers.mdtransaction-synchronization.md
tile.json

transaction-synchronization.mddocs/

Transaction Synchronization

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.

Capabilities

TransactionSynchronizationManager

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
}

TransactionSynchronization

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")
    );
}

TransactionSynchronizationAdapter

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.

TransactionSynchronizationUtils

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
    );
}

ResourceHolder

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();
}

ResourceHolderSupport

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;
    }
}

ResourceHolderSynchronization

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);
}

Common Patterns

Custom Resource Management

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;
    }
}

Transaction-Aware Caching

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);
        }
    }
}

Resource Cleanup Coordination

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
    }
}

Notes

  • TransactionSynchronizationManager is thread-bound and uses ThreadLocal storage
  • Synchronization must be initialized by the transaction manager (automatically done by AbstractPlatformTransactionManager)
  • Resource binding is primarily for framework code, not application code
  • TransactionSynchronization callbacks are invoked in order determined by getOrder()
  • Always check isSynchronizationActive() before registering synchronizations
  • Resources should be unbound after use to prevent memory leaks
  • bindSynchronizedResource() (since Spring 7.0) automatically unbinds after transaction completion