avatarlance

Summary

The article discusses common Spring transaction failure scenarios and their solutions, emphasizing the importance of understanding Spring transaction principles for Java developers.

Abstract

The article "6 Spring Transaction Failure Scenarios that Everyone Has Encountered" provides insights into the intricacies of Spring transactions, which are crucial for Java Software Engineers to grasp for both interview preparation and writing robust code. It outlines six typical situations where Spring transactions might fail, including handling checked exceptions, self-caught exceptions, intra-class method calls, use of final or static, non-public methods, and incorrect transaction propagation. The author explains the underlying principles and offers practical solutions, such as configuring the rollbackFor attribute, avoiding self-caught exceptions, using proper class proxying, and selecting appropriate transaction propagation behaviors. By understanding these scenarios, developers can avoid common pitfalls and ensure that their transaction management is both effective and reliable.

Opinions

  • The author believes that a deeper understanding of Spring transactions is essential for junior engineers to evolve into senior developers.
  • It is implied that many developers might not fully grasp the principles of Spring transactions, leading to common issues that could be avoided with more knowledge.
  • The article suggests that even experienced developers can overlook simple yet critical aspects of transaction management, such as method visibility and exception handling.
  • The author emphasizes the importance of using Spring's declarative transactions correctly and knowing when to switch to programmatic transactions for better control.
  • There is an underlying frustration with Spring's limitations when dealing with final or static methods, highlighting a potential area for improvement in the framework.
  • The author advocates for the careful use of transaction propagation strategies to prevent unexpected transaction behaviors.

6 Spring Transaction Failure Scenarios that Everyone Has Encountered

When you encounter the problem of spring transaction failure, just read this article.

As a Java Software Engineer, I believe everyone is familiar with spring transaction. However, many junior engineers may only have a simple understanding of spring transactions. If we want to grow into senior java development engineers, whether in order to cope with the interview or write more elegant code, we should still know more about the use details of spring transactions. A colleague of mine encountered a problem of spring transaction failure the other day. He couldn’t solve it and came to consult me. In fact, if he had known the principle of spring transaction, he might not have had these troubles. Today, we will summarize the spring transaction failure scenarios and propose solutions.

Spring Transaction Principle

Spring transaction do not implement transactions. Spring transaction still depends on database transactions. Without the support of database transactions, spring transaction will not take effect.

Spring transaction only provides a set of abstract transaction management functions based on the capabilities of AOP (we all know that the core of AOP is the dynamic agent). If you do not use spring transaction but directly use JDBC to operate transactions, the pseudocode may be as follows:

With spring transactions, you only need an annotation @Transaction (or use a programmatic transaction @TransactionTemplate). Next, let’s get to the point and see what scenarios will cause spring transactions to fail.

Throw Checked Exception

If the rollbackFor of @transaction is not specifically specified, the spring will only roll back when it encounters RuntimeException or error.

After knowing the reason, the solution is also very simple. Configure the rollbackFor attribute, such as@Transactional(rollbackFor = Exception.class).

The Business Method Caught the Exception Itself

In this scenario, the reason for transaction failure is also very simple, because spring catches exceptions and determines whether to rollback according to the exception type.

So if you have caught exceptions yourself, spring can’t do anything about it. Looking at the above code, you may think that you can’t make such a stupid mistake with such a simple problem, but what I want to tell you is that almost half of the people around me have been troubled by this scene.

When writing business code, the code may be complex, and there are many nested methods. If you are not careful, this problem is likely to be triggered. For a very simple example, suppose you have an audit function. After each method is executed, the audit results are saved in the database. Then the code may be written like this.

In the above example, the transaction will fail. The reason is that the transaction aspect of spring has the lowest priority, so if the exception is caught by the aspect, spring naturally cannot process the transaction normally, because the transaction manager cannot catch the exception.

See, although we know that the business code cannot catch exceptions by itself when dealing with transactions, as long as the code becomes complex, we are likely to make mistakes again, so we should be careful when dealing with transactions, or not use declarative transactions, and use programmatic transaction — transactionTemplate.execute()

Method Calls Within the Same Class

This is also a scene that is easy to make mistakes. The reason for transaction failure is also very simple, because spring’s transaction management function is implemented by dynamic proxy, while spring uses JDK dynamic proxy by default, and JDK dynamic proxy adopts the way of interface implementation, calling the target class through reflection.

Use the real class instead of the proxy class when doInsert() calling, so the transaction will fail. The solution can be to directly add the @transaction annotation to saveUser()or add the @EnableAspectJAutoProxy(exposeProxy = true) to the startup class, which is implemented by Cglib proxy by default.

Method Uses final or static

If spring uses Cglib proxy implementation (for example, your proxy class does not implement an interface), and your business method happens to use the final or static keyword, then the transaction will also fail.

More specifically, it should throw exceptions, because Cglib uses bytecode enhancement technology to generate subclasses of the proxied class and rewrite the methods of the proxied class to implement the proxy. If the methods of the methods proxied use the final or static keywords, the subclasses cannot rewrite the methods proxied.

Here’s a complaint for spring. I really didn’t expect any reason to use the final or static keywords in the service layer methods.

Method is No-Public

If the method is not public, spring transactions will also fail, because spring’s transaction management source code AbstractFallbackTransactionAttributeSource There is a judgment in computeTransactionAttribute(). If the target method is not public, then the TransactionAttribute returns null. The solution is to change the current method access level to the public.

Wrong Use of Transaction Propagation

The propagation mechanism of spring transactions refers to the strategy of determining how transactions should propagate in multiple transaction methods when they call each other. Spring provides seven transaction propagation mechanisms: REQUIRED, SUPPORTS, MANDATORY、REQUIRES_NEW, NOT_SUPPORTED, NEVER, NESTED. If you don’t know the principle of these propagation strategies, it is likely to lead to transaction failure.

In the above example, if the user fails to insert, it will not cause saveAddress() rollback, because the propagation used here is REQUIRES_NEW, The principle of the REQUIRES_NEW propagation strategy is that if there is no transaction in the current method, a new transaction will be created.

If a transaction already exists, the current transaction will be suspended and a new transaction will be created. The parent transaction will not be submitted until the current transaction is completed.

If an exception occurs in the parent, the submission of child transactions will not be affected. The solution is also very simple. Change the transaction propagation strategy to the default REQUIRED. The REQUIRED principle is that if a transaction is added to a transaction at present, if not, a new transaction will be created, and the parent transaction and the called transaction are in the same transaction. Even if the called exception is caught, the whole transaction will still be rolled back.

This article lists six scenarios of sping transaction failure, which I believe many friends may have encountered. The reason for the failure is also explained in detail. I hope you have a new understanding of the spring transaction. Thank you for reading.

Spring
Java
Programming
Coding
Software Development
Recommended from ReadMedium