preface


Believe everyone in a transaction failure scenario, it is the Spring from the call, is in the Service method, calls another add @ Transactional annotation methods, found the transaction fails, then how do you solve?

Things to review

It was an afternoon when I forgot what the weather was like, and suddenly a little red dot popped out.

The transaction failed!

Don’t panic! Don’t panic!

Finally my partner chose to draw away, is my tool class not fragrant?

Of course the story works out perfectly, problem solved.

The transaction

Transactions are needed when development involves operating on multiple tables at the same time to ensure that both operations either succeed or fail together.

Declarative transactions based on the @Transactional annotation are commonly used today.

In the process of using transactions, there are several considerations:

  1. Transactions are valid only when applied to public methods;
  2. Transactions need to be invoked from the outside, and Spring calls themselves are invalidated;
  3. It is recommended that the Transactional annotation @Transactional be generally added to the implementation class.

Of course this a few words is not to say me, somebody else official document but clear specification!

This illustrates that the @Transactional annotation should only be applied to methods that have public visibility. No errors are raised if used against methods that are protected, private O, or package-visible, but the annotated method does not show configured transaction Settings.

Put it bluntly, it is you used, will not report wrong, but not effective!

As for the recommendation to be applied to the implementation class, this is just a recommendation, but if applied to an interface class or interface method, only configuring an interface-based proxy will take effect. So it’s better to stick to the implementation class or implementation method.

Because the proxy mode intercepts only external method calls that come in through the proxy, self-invoking transactions are not effective.

The official explanation is relatively simple and clear, although I do not understand, but it does not affect my screenshots.

I’ll cut off another one then…

The actual use

But in development, this is often the case with friends!

Originally wrote their own code on a lump of smelly and long, there are all kinds of check, check, query, verification and so on, just thinking about to a transaction, so that the scope of the transaction package is minimal, just add transaction at the same time update it!

The IDEA is not private, so I change it to public.

Obviously transactions are not valid.

Put the updated code inside the long, stinky code, make it stinky and longer, and annotate it with the @Transactional annotation. Perfect solution!

Please leave that piece of code alone! Here’s how to do it.

Solution 1

Can’t I just make an external call instead?

Declare a Service that puts the logic behind updating the table.

I usually like to use this method.

Solution 2

With programmatic transactions, as mentioned above, with declarative transactions, this and that, I can always change the way!

You see, I’ve also changed the method to private, and the transaction is in effect. Perfect solution!

In fact, this method is also very good!

Solution 3

What if you want to use annotations and call from yourself?

But… You can go to a little trouble.

We can refer to the way of programmatic transaction, which is not to let the self call, I call the external method, and then the external method call back to me.

@Component
public class TransactionalComponent {

    public interface Cell {

        void run(a) throws Exception;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void required(Cell cell) throws Exception { cell.run(); }}Copy the code

This can then be called via TransactionalComponent and can also use lambda expressions.

It is possible to do an iteration with this version, using static method calls instead of injecting @AutoWired every time.

public class TransactionalUtils {
    
    private static volatile TransactionalComponent transactionalComponent;

    private static synchronized TransactionalComponent getTransactionalComponent(a) {
        if (transactionalComponent == null) {
            // Get transactionalComponent from the container
            transactionalComponent = ApplicationContextUtils.getBean(TransactionalComponent.class);
        }
        return transactionalComponent;
    }

    public static void required(TransactionalComponent.Cell cell) throws Exception { getTransactionalComponent().required(cell); }}Copy the code

The utility class TransactionalUtils allows transactions to be performed directly by calling static methods.

conclusion

conclusion

This paper mainly introduces why transaction failure occurs and how to avoid transaction failure, and provides three ways to solve the problem of self-invoking transaction failure. Any deficiencies are welcome to be corrected.

The relevant data

  1. IO /spring-fram…