Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the failure scenarios of @ Transactional in spring

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

I would like to share with you the failure scenarios of @ Transactional in spring. I believe most people don't know much about it, so share this article for your reference. I hope you will learn a lot after reading this article. Let's learn about it.

Failure scenario set 1: the agent does not take effect

The urination of annotation parsing in Spring is agent-based, and if the target method cannot be proxied by Spring, it cannot be transacted by Spring.

Spring generates proxies in two ways:

Interface-based JDK dynamic proxy requires that the target proxy class needs to implement an interface before it can be proxied.

CGLIB proxy based on the subclass of the target class

Spring before 2.0, if the target class implements the interface, it uses the JDK dynamic proxy mode, otherwise the proxy is generated by the CGLIB subclass.

After version 2.0, if the specified spring.aop.proxy-tartget-class value is not displayed in the configuration file, the proxy is generated by default as CGLIB, as shown in the following figure

Following the agent's way of thinking, let's take a look at what happens when transaction control fails because the agent does not take effect.

(1) Mark the comments on the interface method

@ Transactional supports tagging on methods and classes. Once marked on the interface, if the proxy mode of the corresponding interface implementation class is CGLIB, the proxy of the target class will be generated by generating subclasses, which will not be resolved to @ Transactional, so the transaction will become invalid.

We still make relatively few such mistakes. Basically, we will annotate the implementation class methods of the interface, and this is not officially recommended.

(2) classes or methods modified by final and static keywords

CGLIB generates the proxy class by generating the subclasses of the target class. after being modified by final and static, it can not inherit the methods of the parent class and the parent class.

(3) Internal call of class method

The management of the transaction takes effect through the execution of the agent, and if it is an internal call to the method, it will not follow the agent logic and will not be called.

For example

The internal method createUser1 is called in createUser, and the transaction propagation policy is set to: REQUIRES_NEW on the createUser1 method, but because it is an internal direct call, createUser1 cannot manage the transaction without a proxy. Inserting data fails after the createUser1 method throws an exception.

But this kind of operation seems to be quite common in the process of our business development. How can we ensure its success?

Method 1: create a new Service and migrate the method. It's a bit of a Muggle.

Method 2: inject yourself into the current class and call createUser1 through the injected userService call

Method 3: get the proxy object through AopContext.currentProxy ()

The reason is similar to mode 2, which is to access internal methods through proxies

(4) the current class is not managed by Spring

There is nothing to say about this, it is not managed by Spring as a bean in the IOC container, let alone proxied by transaction aspects.

This kind of Bug looks stupid, but maybe someone did make a mistake.

Failure scenario set 2: functions that are not supported by the framework or the underlying layer

This type of failure scenario focuses on the internal support of the framework itself when parsing @ Transactional. If you are using a scenario that is not supported by the framework, the transaction will not work.

(1) methods of non-public modification

We make a breakpoint on any method marked @ Transactional, and we can see the transaction pointcut in idea as shown in the following figure

Click to go to this method, and there is a call at the beginning

Keep going in.

You can see this sentence.

Non-public-decorated methods for transaction management are not supported.

(2) Multi-thread call

With the same operation as above, we can enter the TransactionAspectSupport.prepareTransactionInfo method layer by layer.

Pay attention to the following passage

From this we know that the transaction information is bound to the thread.

Therefore, in a multithreaded environment, the information of the transaction is independent, which will lead to differences in Spring taking over transactions.

We should pay special attention to this scene!

Let me give you an example.

Main thread A calls thread B to save the data with Id 1, and then main thread A waits for thread B to complete execution and then queries the data with id 1 through thread A.

At this point, you will find that the data with id 1 cannot be queried in main thread A. Because these two threads are in different Spring transactions, it essentially causes them to exist in different transactions in Mysql.

Through MVCC in Mysql, the thread can only read the data smaller than the current transaction number when the snapshot is read. In thread B, it is obvious that the transaction number is larger than thread A, so the data cannot be queried.

(3) the database itself does not support transactions.

For example, Mysql's Myisam storage engine does not support transactions, only the innodb storage engine supports it.

The probability of this problem is extremely small, because the innodb storage engine is used by default after Mysql5.

However, if there is a misconfiguration or a history project, and you find that no matter how the transaction matches, remember to see if the storage engine itself supports transactions.

(4) unopened business

This is also a Muggle problem, which no longer exists in Springboot projects, and transaction management is enabled by default in DataSourceTransactionManagerAutoConfiguration.

However, in the MVC project, you also need to manually configure transaction-related parameters in the applicationContext.xml file. If you forget to configure, the transaction will certainly not take effect.

3. Failure scenario 3: incorrect use of @ Transactional

Attention, the following are high-frequency Bug!

(1) the mechanism of error propagation

Spring supports seven communication mechanisms, which are:

The transaction propagation mechanism that is not supported above is: PROPAGATION_SUPPORTS,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER.

If these three modes of propagation are configured, the transaction will not be rolled back when an exception occurs.

(2) incorrect setting of rollbackFor attribute

By default, transactions roll back only run-time exceptions and Error, not checked exceptions (such as IOException).

So if an IO exception is thrown in the method, the transaction will also fail to roll back by default.

We can do full exception catch by specifying @ Transactional (rollbackFor = Exception.class).

(3) the exception is caused by internal catch

UserService

UserService1

As shown above, the code UserService calls the method in UserService1 and catches the exception thrown in UserService1.

You will see an error in the console:

Org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

By default, the transaction propagation mechanism for methods marked with @ Transactional annotations is REQUIRED, which is characterized by supporting the current transaction, that is, joining the current transaction. We start the transaction in UserService, and then throw an exception in UserService1 to roll back the transaction in UserService, marking it as read-only.

But in UserSevice we catch an exception, and the transaction on UserService is considered to commit the transaction normally. Finally, when it is found that the transaction is read-only and has been rolled back on commit, the above exception is thrown.

So if you need to catch a specific exception here, remember to throw the exception again so that the outermost transaction is aware of it.

(4) nested transactions

Above, I want to roll back UserService and UserService1 at the same time. However, there will also be such a scenario where you only want to roll back the database operations reported in UserService1 without affecting the data storage in the main logic UserService.

There are two ways to implement the above logic:

1. The whole method directly in UserService1 is wrapped in try/catch.

two。 Using Propagation.REQUIRES_NEW propagation mechanism in UserService1

IV. Summary

This article analyzes 12 scenarios of invalidation in the use of @ Transactional annotations.

Finally, the @ Transactional annotation is fragrant, but under complex business logic, in order to better manage transactions and control the fine granularity of business transactions, I recommend that you use programmatic transactions.

The above is all the content of the article "what are the failure scenarios of @ Transactional in spring". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report