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 reasons for the invalidation of @ Transactional annotations

2025-03-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

What are the reasons for the invalidation of @ Transactional annotations? for this problem, this article introduces the corresponding analysis and solutions in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible way.

I. Affairs

Transaction management is an indispensable part of system development. Spring provides a good transaction management mechanism, which is mainly divided into programmatic transactions and declarative transactions.

Programmatic transaction: refers to manually managing transaction commit, rollback and other operations in the code. The code is more intrusive, as shown in the following example:

Try {/ / TODO something transactionManager.commit (status);} catch (Exception e) {transactionManager.rollback (status); throw new InvoiceApplyException ("exception failure");}

Declarative transactions: based on the aspect-oriented AOP, it decouples the specific business from the transaction processing, and the code intrusiveness is very low, so declarative transactions are often used in actual development. There are also two ways to implement declarative transactions, one is based on TX and AOP xml configuration files, and the other is based on @ Transactional annotations.

@ Transactional @ GetMapping ("/ test") public String test () {int insert = cityInfoDictMapper.insert (cityInfoDict);}

Second, @ Transactional introduction

1. Where can @ Transactional annotations be used?

@ Transactional can act on interfaces, classes, and class methods.

Acting on a class: when the @ Transactional note is liberated on a class, it means that all public methods of that class are configured with the same transaction attribute information.

Acting on the method: when the class is configured with @ Transactional and the method is configured with @ Transactional, the transaction of the method overrides the transaction configuration information of the class.

Working on interfaces: this method is not recommended, because once marked on Interface and Spring AOP is configured to use CGLib dynamic proxy, the @ Transactional annotation will be invalidated

@ Transactional @ RestController @ RequestMapping public class MybatisPlusController {@ Autowired private CityInfoDictMapper cityInfoDictMapper; @ Transactional (rollbackFor = Exception.class) @ GetMapping ("/ test") public String test () throws Exception {CityInfoDict cityInfoDict = new CityInfoDict (); cityInfoDict.setParentCityId (2); cityInfoDict.setCityName ("2"); cityInfoDict.setCityLevel ("2"); cityInfoDict.setCityCode ("2") Int insert = cityInfoDictMapper.insert (cityInfoDict); return insert + "";}}

2. What are the attributes of @ Transactional?

Propagation attribute

Propagation represents the propagation behavior of the transaction. The default value is Propagation.REQUIRED. Other attribute information is as follows:

Propagation.REQUIRED: join a transaction if it currently exists, and create a new transaction if it does not exist. (that is, if both method An and method B are annotated, in the default propagation mode, method A calls method B internally, merging the transactions of the two methods into one transaction.)

Propagation.SUPPORTS: join a transaction if it currently exists; if no transaction exists, continue to run in a non-transactional manner.

Propagation.MANDATORY: join a transaction if it currently exists, or throw an exception if it does not exist.

Propagation.REQUIRES_NEW: recreate a new transaction and pause the current transaction if it exists. (when the a method in class A uses the default Propagation.REQUIRED mode, the b method in class B plus the Propagation.REQUIRES_NEW mode, and then calls the b method in the a method to operate the database, however, after the a method throws an exception, the b method does not roll back because Propagation.REQUIRES_NEW suspends the transaction of the a method.)

Propagation.NOT_SUPPORTED: runs in a non-transactional manner, pausing the current transaction if there is a current transaction.

Propagation.NEVER: runs in a non-transactional manner, throwing an exception if a transaction currently exists.

Propagation.NESTED: the same effect as Propagation.REQUIRED.

Isolation attribute

Isolation: the isolation level of the transaction. The default value is Isolation.DEFAULT.

Isolation.DEFAULT: use the default isolation level of the underlying database.

Isolation.READ_UNCOMMITTED

Isolation.READ_COMMITTED

Isolation.REPEATABLE_READ

Isolation.SERIALIZABLE

Timeout attribute

Timeout: the timeout of the transaction. The default value is-1. If the time limit is exceeded and the transaction has not been completed, the transaction is automatically rolled back.

ReadOnly attribute

ReadOnly: specifies whether the transaction is read-only. The default value is false;. In order to ignore methods that do not require a transaction, such as reading data, you can set read-only to true.

RollbackFor attribute

RollbackFor: used to specify the type of exception that can trigger a transaction rollback. Multiple exception types can be specified.

NoRollbackFor attribute * *

NoRollbackFor: throws the specified exception type without rolling back the transaction, or you can specify multiple exception types.

2. @ Transactional failure scenario

Next, let's analyze the scenarios in which the @ Transactional annotation will fail with the specific code.

1. @ Transactional is applied to non-public modified methods

If Transactional annotations are applied to methods that are not modified by public, Transactional will be invalidated.

Insert a picture description here

The reason for the failure is that during the Spring AOP agent, TransactionInterceptor (transaction interceptor) as shown in the above figure intercepts before and after the target method is executed, and the intercept method of DynamicAdvisedInterceptor (the inner class of CglibAopProxy) or the invoke method of JdkDynamicAopProxy will indirectly call the computeTransactionAttribute method of AbstractFallbackTransactionAttributeSource to obtain the transaction configuration information annotated by Transactional.

Protected TransactionAttribute computeTransactionAttribute (Method method, Class targetClass) {/ / Don't allow no-public methods as required. If (allowPublicMethodsOnly () & &! Modifier.isPublic (method.getModifiers () {return null;}

This method checks whether the modifier of the target method is public, and if it is not public, it does not get the property configuration information of @ Transactional.

Note: protected, private modified methods on the use of @ Transactional annotation, although the transaction is invalid, but there will not be any error report, this is a mistake-tolerant point.

2. @ Transactional comment property propagation setting error

This failure is due to a configuration error, and if the following three propagation are misconfigured, the transaction will not be rolled back.

TransactionDefinition.PROPAGATION_SUPPORTS: if there is a transaction, join it; if there is no transaction, continue to run in a non-transactional manner.

TransactionDefinition.PROPAGATION_NOT_SUPPORTED: runs in a non-transactional manner, suspending the current transaction if there is a current transaction.

TransactionDefinition.PROPAGATION_NEVER: runs in a non-transactional manner, throwing an exception if a transaction currently exists.

3. @ Transactional comment property rollbackFor setting error

RollbackFor can specify the type of exception that can trigger a transaction rollback. Spring rolls back the transaction by default when it throws an unchecked unchecked exception (an exception inherited from RuntimeException) or Error; other exceptions do not trigger a rollback transaction. If you throw other types of exceptions in a transaction but expect Spring to roll back the transaction, you need to specify the rollbackFor property.

Insert a picture description here

/ / you want custom exceptions to be rolled back to @ Transactional (propagation= Propagation.REQUIRED,rollbackFor= MyException.class

If the exception thrown in the target method is a subclass of the exception specified by rollbackFor, the transaction is also rolled back. The Spring source code is as follows:

Private int getDepth (Class exceptionClass, int depth) {if (exceptionClass.getName () .contains (this.exceptionName)) {/ / Found it! Return depth;} / / If we've gone as far as we can go and haven't found it... If (exceptionClass = = Throwable.class) {return-1;} return getDepth (exceptionClass.getSuperclass (), depth + 1);}

4. Method calls in the same class invalidate @ Transactional

In development, it is inevitable to call methods in the same class, for example, there is a class Test, one of its methods, AMagi A, then calls method B of this class (whether method B is decorated with public or private), but method A does not declare annotated transactions, while method B has. After method An is called externally, the transaction of method B will not work. This is also a place where mistakes are often made.

Then why did this happen? In fact, this is due to the use of the Spring AOP proxy, because the transaction method is managed by the proxy object generated by Spring only when the transaction method is called by code other than the current class.

/ / @ Transactional @ GetMapping ("/ test") private Integer A () throws Exception {CityInfoDict cityInfoDict = new CityInfoDict (); cityInfoDict.setCityName ("2"); / * * B insert data with field 3 * / this.insertB () / * An insert data with field 2 * / int insert = cityInfoDictMapper.insert (cityInfoDict); return insert;} @ Transactional () public Integer insertB () throws Exception {CityInfoDict cityInfoDict = new CityInfoDict (); cityInfoDict.setCityName ("3"); cityInfoDict.setParentCityId (3); return cityInfoDictMapper.insert (cityInfoDict);}

5. The exception was "eaten" by your catch and caused @ Transactional to fail.

This is the most common @ Transactional annotation failure scenario.

@ Transactional private Integer A () throws Exception {int insert = 0; try {CityInfoDict cityInfoDict = new CityInfoDict (); cityInfoDict.setCityName ("2"); cityInfoDict.setParentCityId (2); / * * An insert data with field 2 * / insert = cityInfoDictMapper.insert (cityInfoDict) / * B insert data with field 3 * / b.insertB ();} catch (Exception e) {e.printStackTrace ();}}

If an exception is thrown inside method B, and method A try catch the exception of method B at this time, can the transaction be rolled back normally?

Answer: no!

An exception is thrown:

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

Because when an exception is thrown in the ServiceB, the ServiceB identifies that the current transaction requires a rollback. But in ServiceA, because you manually catch this exception and handle it, ServiceA believes that the current transaction should be normal commit. Inconsistencies occur at this point, and because of this, the previous UnexpectedRollbackException exception is thrown.

The transaction of spring starts before the business method is called, and the commit or rollback is executed after the business method is executed. Whether the transaction is executed depends on whether or not a runtime exception is thrown. If a runtime exception is thrown and there is no catch in your business method, the transaction will be rolled back.

Generally speaking, there is no need for catch exceptions in business methods. If catch is required to throw throw new RuntimeException (), or the exception type @ Transactional (rollbackFor=Exception.class) is specified in the comments, otherwise the transaction will fail and the data commit will cause data inconsistencies, so sometimes try catch will be superfluous.

6. Database engine does not support transactions

The probability of this situation is not high, and whether the transaction can take effect or not is the key to whether the database engine supports transactions. Commonly used MySQL databases use the innodb engine that supports transactions by default. Once the database engine switches to a myisam that does not support transactions, the transaction is fundamentally invalid.

The answers to the questions about the reasons for the invalidation of @ Transactional annotations are shared here. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more relevant knowledge.

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

Database

Wechat

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

12
Report