Spring transaction extension mechanism, 2021 popular whole network series

Next, let's analyze the processing of connection resources by transaction operations, that is, the management of resources (resources attribute) by transaction synchronization manager in transaction processing.

2. Spring transaction processing

The TransactionSynchronizationManager#bindResource binding connects resources to the resources attribute in TransactionSynchronizationManager. The following is the binding sequence diagram:

TransactionInterceptor is Spring's proxy entry for transaction method processing, which abstracts JDBC transactions:

// Get connection
Connection conn = DataSource.getConnection();

// Set auto submit false
conn..setAutoCommit(false);

try {
	// Business operation
	doSomething();
} catch (Exception e) {
	// Rollback transaction
	conn.rollback();
}
// Commit transaction
conn.commit();

TransactionAspectSupport#invokeWithinTransaction

TransactionAspectSupport#invokeWithinTransaction is the processing of Spring. Let's briefly analyze its processing process:

The logic of the above code is as follows:

  • TransactionAttributeSource#getTransactionAttribute obtains transaction related information (TransactionAttribute). Take annotated transactions as an example to see if there is @ Transactional annotation on the method acquisition class.

  • Get the platform transaction manager configured in the Spring container, and then the real transaction processing

  • Create transaction information (TransactionInfo), which contains transaction manager (platform transaction manager) and transaction related information (TransactionAttribute)

  • This is followed by Spring's abstract operations on transactions, including setting auto commit false, business operations, abnormal rollback transactions and normal commit transactions

Let's get back to the point. Spring binds the database connection to the ThreadLocal variable through the transaction synchronization manager #bindresource by creating the transaction info. Then, other database operations marked into a transaction can obtain the connection through the transaction synchronization manager #getresource.

Database transactions are connection based, and Spring's transaction implementation for multiple database operations is based on ThreadLocal. Therefore, multithreading cannot be used in transaction operations

3. Extension of Spring transactions – TransactionSynchronization

In the TransactionSynchronizationManager class above, we know that its current thread also saves the TransactionSynchronization object during transaction operation. Along with Spring, this object will have corresponding extensions for each life cycle of transaction processing.

TransactionSynchronization.java

public interface TransactionSynchronization extends Flushable {

	/** Transaction commit status */
	int STATUS_COMMITTED = 0;

	/** Transaction rollback status */
	int STATUS_ROLLED_BACK = 1;

	/**System abnormal state */
	int STATUS_UNKNOWN = 2;

	void suspend();

	void resume();

	void flush();

	// Before transaction commit
	void beforeCommit(boolean readOnly);

	// Before the transaction succeeds or the transaction is rolled back
	void beforeCompletion();

	// After the transaction is successfully committed
	void afterCommit();

	// After the operation is completed (including transaction success or transaction rollback)
	void afterCompletion(int status);

}

The application scenario in the transaction extension project of transaction is to send a message to MQ after the order is successful. Because the transaction is bound to the database connection, if you put the sending message and database operation in one transaction. When sending messages for too long, it will occupy the database connection, so it is necessary to decouple the database operation from sending messages to MQ. You can use the method of TransactionSynchronization#afterCommit to send messages to MQ when the data is successfully saved to the database and the transaction is committed.

@Transactional
public void finishOrder(Order order){
	// Order modified successfully
	updateOrderSuccess(order);

	// Send message to MQ
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
       @Override
       public void afterCommit() {
           mqService.send(order);
       }
    });
}

After the transaction is successfully committed, the message will be sent to MQ without occupying database connection resources.

4. Spring transaction extension – @ TransactionalEventListener

After Spring framework 4.2, @ TransactionalEventListener can also be used to process database transactions. After successful submission, operations can be performed. This approach is more elegant than transaction synchronization. It is used as follows:

 @Transactional
	public void finishOrder(Order order){
		// Order modified successfully
		updateOrderSuccess(order);

		// Publishing Spring Event events
	    applicationEventPublisher.publishEvent(new MyAfterTransactionEvent(order));
	}

    @Slf4j
    @Component
    private static class MyTransactionListener {
        @Autowired
        private MqService mqService;

        @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
        private void onHelloEvent(MyAfterTransactionEvent event) {
            Order order = event.getOrder();
            mqService.send(order);
        }
    }

    // Define an event, inherited from ApplicationEvent 
    private static class MyAfterTransactionEvent extends ApplicationEvent {

        private Order order;

        public MyAfterTransactionEvent(Object source, Order order) {
            super(source);
            this.order = order;
        }

        public Order getOrder() {
            return order;
        }
    }

Its implementation principle is that when the method of Spring Bean is marked with the ApplicationListenerMethodTransactionalAdapter created through TransactionalEventListenerFactory#createApplicationListener, then the implementation class TransactionSynchronizationEventAdapter of TransactionSynchronization is created in the event callback. And register the TransactionSynchronizationEventAdapter to the current thread through TransactionSynchronizationManager.registerSynchronization.

n implementation class TransactionSynchronizationEventAdapter. And register the TransactionSynchronizationEventAdapter to the current thread through TransactionSynchronizationManager.registerSynchronization.

Tags: Java Hibernate Spring Back-end Programmer

Posted on Tue, 23 Nov 2021 22:40:53 -0500 by patrickrock