Listener on transaction start

transactionaleventlistener example
spring transactionsynchronizationmanager
spring data jpa event handler
spring application event asynchronous
transactional vs synchronized
spring boot synchronized

I am looking for a clean solution to have a listener for transaction start. That means I would like the listener to be a bean (component) in the spring context that would receive an event on transaction start from TransactionPlatformManager or Hibernate Session or something similar, at the point where a new transaction is started.

Something along:

@Component
class TransactionListener implements ?? {

    @Autowired
    private Something x;

    public void onTransactionBegin(...) {
        x.doSomething()
    }

}

To be concrete, I am mitigating a system wide problem and I need to set a thread local when transaction starts, so I can access that thread local further in the processing of hibernate entities to retrieve info.

I looked into sources and found no traces for such listener to be achievable. The only solution I found was to subclass HibernateTransactionManager and its doBegin() method, which I don't find particularly nice.

Spring have some transaction callbacks in its TransactionSynchronization, however as you correctly have noticed, there is no callback for transaction start, my mistake.

As far as I know, Spring will not let you know when transactions start, although this may vary from different implementations PlatformTransactionManager. If you want to hook into Spring transaction, I believe you are left with

  1. Subclass the transaction manager and invoke some callback
  2. Create an advice for @Transactional with spring-aop (this will only work if you use annotations, obviously)

If you're using Hibernate, you might have some luck with afterTransactionBegin in https://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Interceptor.html#afterTransactionBegin(org.hibernate.Transaction)

java - Listener on transaction start, I am looking for a clean solution to have a listener for transaction start. That means I would like the listener to be a bean (component) in the spring context that  The listener will start a TCP listen on the port number identified by the PORT=nnnn statement in the EZACICD TYPE=LISTENER record. You would then make a TCP connection to this port number. The client would submit the transaction that it wishes to execute. The client must submit the transaction request in the IBM listener input format.

I had a similar problem where I wanted to log the Oracle session id as soon as a transaction starts, in order to investigate some issue we have.

In the end I figured that, since Spring uses PlatformTransactionManager, you can access all information by customizing it.

The first thing to do is to identify which implementation you are using. In our case, it was a simple JpaTransactionManager declared in a @Configuration class, so it was rather easy.

Once you have done this, notice that you can enable debug or trace logging on this class, which already provides a lot of transaction status information if your goal is to debug an issue.

If this is not enough, it's easy to subclass it and replace the previous one. Then just override the methods you want to intercept like doBegin() or prepareSynchronization().

See for instance my implementation:

@Slf4j
public class LoggingJpaTransactionManager extends JpaTransactionManager {
    @Autowired
    private EntityManager entityManager;

    LoggingJpaTransactionManager(EntityManagerFactory emf) {
        super(emf);
    }

    @Override
    protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
        super.prepareSynchronization(status, definition);
        if (status.isNewTransaction() && log.isInfoEnabled()) {
            Query query = entityManager.createNativeQuery("select sys_context('USERENV','SID') from dual");
            Object sessionId = query.getSingleResult();
            log.info("Started a new transaction on session id {}", sessionId);
            TransactionSynchronizationManager.registerSynchronization(…);
        }
    }
}

Note: I chose to override prepareSynchronization() instead of doBegin() because it allows to use the TransactionSynchronizationManager, which I think remains cleaner to be notified of commit/rollback events. This method is invoked immediately after doBegin() anyway.

Listener on transaction start, Listener on transaction start. transactionaleventlistener example spring transactionsynchronizationmanager spring transaction propagation spring data jpa event  CSTRANID. This parameter is specific to the enhanced version of the Listener and specifies the default child server transaction that the Listener starts. For enhanced listener message (ELM) Link support, this value should be set to MSCS to conform to the samples that Microsoft delivers with the product.

This works for me so far.

@Aspect
@Component
public class StartTransactionInterceptor {

    @Pointcut("target(org.springframework.transaction.PlatformTransactionManager)")
    public void isPlatformTransactionManager() {
    }

    @Pointcut("execution(org.springframework.transaction.TransactionStatus getTransaction("
            + "org.springframework.transaction.TransactionDefinition)))")
    public void getsTransaction() {
    }

    @Around("isPlatformTransactionManager() && getsTransaction()")
    public Object registerSynchronization(ProceedingJoinPoint joinPoint) throws Throwable {
        TransactionStatus value = (TransactionStatus)joinPoint.proceed();
        if (value.isNewTransaction()) {
            // send some application event to others who are interested
        }
        return value;
    }
}

Alternatively, you can use Spring's SimpleTransactionScope and scope a bean for transaction scope. The bean would get lazily instantiated as others call into DealWithStuffPerTx.addMoreStuff(Object) below within a transaction.

@Configuration
public class TransactionScopeConfig implements BeanFactoryPostProcessor {

    public static final String NAME = "tx";
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerScope(NAME, new SimpleTransactionScope());
    }
}

@Component
@Scope(value = TransactionScopeConfig.NAME, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DealWithStuffPerTx extends TransactionSynchronizationAdapter {

    public void addMoreStuff(Object stuff) {
    }

    @Override
    public void afterCommit() {
        // deal with stuff
    }

    @PostConstruct
    public void init() {
        TransactionSynchronizationManager.registerSynchronization(this);
    }
}

Transaction Synchronization and Spring Application Events, Using an example that focuses on transaction synchronization issues, this tutorial Application Events: Understanding @TransactionalEventListener is good (​note the assumption at the beginning of the previous chapter),  Starting a listener. To start a listener, use the following procedure at the Sybase TCP Maintenance Transaction window. Starting a listener. In the Action field, type S. Press Enter. The listener starts and you see the following message: *** Request accepted *** Stopping a listener

TransactionalEventListener (Spring Framework 5.2.7.RELEASE API), An EventListener that is invoked according to a TransactionPhase . If the event is not published within an active transaction, the event is discarded unless the  The ESD6 Gatewayless Handler transaction is started by the listener during its initialization routine, and terminated by the listener when it is shut down. While in operation, the handler maintains a socket pool to hold connections not currently “owned” by an executing RPC transaction.

16. Transaction Management - Project Metadata API Guide, 16.1 Introduction to Spring Framework transaction management all methods on starting with 'get' are to execute in the context of a read-only When you do so, the listener will be bound to the commit phase of the transaction by default. Communications between a CICS region and a CICS® Transaction Gateway uses either the TCP/IP listener or the SNA listener, depending on whether the clients are connected through TCP/IP or SNA. There are two kinds of TCP/IP listeners, one supporting communication over CICS family TCP/IP and the other supporting communication over IPIC over TCP/IP.

6. Event Processing, This means that Event Listeners must be explicitly registered with the Event Bus in order Starting and committing a transaction for each single event has a big  A listener is a special process which establishes a communication path between the client and the oracle instances. Listener process is not a part of the oracle instance but it is a part of the networking process that works with oracle. We can say it listens to the client connection requirements.

Comments
  • The easiest would probably be to create a wrapper for the PlatformTransactionManager and fire those events on the 3 method calls. But why do you need to have this registered? What is it you are trying to do? You mention solving problems but then this seems a bit strange to do.
  • The problem I am facing is irrelevant and it is caused by our big multimodule architecture. If I had a choice to make decisions about the architecture, I would do it differently. But this is not possible in this legacy architecture, without immersive rewrite, that's why I need this.
  • That will notify about all the events, except transaction begin.
  • The aspect solution looked nice, but it unfortunately only works with JDK proxies and not CGLIB class proxies proxies, due to the many final methods in AbstractPlatformTransactionManager, causing NPE's as soon as you try to start a transaction. As far as I understand, the second method cannot intercept transactions globally, it will only work for code that calls addMoreStuff().