There are generally three things to note about the @Transactional annotation:

1. Annotate @Transactional wherever transaction management is required. The @Transactional annotation can be applied to interface definitions and interface methods, class definitions, and class public methods.

2. The @Transactional annotation applies only to methods with public visibility. The @Transactional annotation will not fail if you use it on protected, private, or package-visible methods, but the annotated method will not show configured transaction Settings.

3. Note that the presence of the @Transactional annotation alone does not enable Transactional behavior; it is simply metadata. The configuration element must be used in the configuration file to truly enable transactional behavior.

Recently, I found that the annotation was invalid in the project. After tracing the source code, I found the problem, so I found someone with the same problem on the Internet. The following is the original text, explaining in detail:

Just avoid the limitations of Spring’s current AOP implementation and either declare transactions for both, split them into two classes, or use programmatic transactions directly in methods

[question]

Since using Spring AOP, transaction management is really easy, really easy; Transaction management code is gone, the brain is not sour, the hand is not painful, one breath is fully matched with the transaction; Lightweight and easy to test, hey!” . Whichever way you look at it, lightweight declarative transactions are a great productivity boon. So we “use it all the time.”

, however, a recent project, but met a transaction management problems: there is a service class, its a statement transaction method, make three times a insert SQL operations, but behind rollback when something goes wrong, only to find that the front insert is successful, also said that the statement of the transaction method, is not actually true starting the transaction! What’s going on? Are Spring’s declarative transactions broken?

[fully]

I’ve seen people say that Spring’s transaction configuration doesn’t work, but based on my first reaction and past experience, I always tell them that there must be something wrong with your configuration. So this time, I think, is no exception, probably because the transaction annotations are attached to the interface rather than the implementation method, or, if XML is declared, probably because the expression of the pointcut is not paired.

The Transactional transaction implements the @Transactional transaction annotation declaration. The XML also implements the annotation driver < TX :annotation-driven… /> < span style = “max-width: 100%; clear: both; min-height: 1em;

I was puzzled, so I asked:

Question 1: Does this happen with other methods?

A1: No.

Q2: Is there anything special about this method (method B)?

Answer 2: it is to adjust the background to insert three records, nothing special.

Question 3: Is this method called directly from the Web layer?

Answer 3: No, it is called from another method of the Service class (ServiceA).

Q4: Oh, is the method that calls it configured with a transaction (that might be the problem)?

A4: No.

Question 5: What WEB layer Action (using Struts2) calls method A that does not declare A transaction, and method A calls method B that declares A transaction?

A5: That’s right.

Question 6: You can just add the transaction declaration to method A

A6: Good…

Transactional method A and method B are both in the same transaction. The Transactional method uses A Transactional method to test the Transactional method.

Ok, now to sum up the phenomenon:

The ServiceA class is the Action service for the Web layer

2. The Action calls ServiceA’s method A, which does not declare A transaction (because method A itself is time-consuming and does not require A transaction).

3. Method A of ServiceA calls method B of its own class, and method B declares A transaction, but method B’s transaction declaration is invalid in this case.

4. If A transaction is declared on method A, the transaction takes effect when Action calls method A, and method B automatically participates in the transaction.

I asked him to add the A to the transaction statement and decided to come back and test it himself.

This problem, ostensibly a problem of transaction declaration invalidation, is most likely a problem from the implementation perspective of Spring’s AOP mechanism.

I was thinking about something I discovered long ago when I looked at AOP implementations of Spring: For cglib-enhanced AOP target classes, two objects are created, one for the Bean instance itself and one for the Cglib-enhanced proxy object, not just the latter. I wondered about this, but didn’t pursue it any further.

As we know, There are two ways to implement Spring AOP: 1. Cglib dynamic enhancement, which can be seamlessly switched between in Spring.

The advantage of Java proxy is that it does not rely on third-party JAR packages, but the disadvantage is that it cannot proxy classes, only interfaces.

Spring abstracts these two implementations through the AopProxy interface, implementing a consistent AOP approach:

Now, this abstraction also carries a drawback, which is that it negates Cglib’s ability to directly create enhanced subclasses of ordinary classes. Spring effectively treats Cglib’s dynamically generated subclasses as ordinary proxy classes, which is why two objects are created. The following figure shows the actual invocation of Spring’s AOP proxy class:

Therefore, methodB was not notified by AopProxy from the above analysis,

The net result: classes enhanced by Spring’s AOP will not have enhancement notifications on the invoked methods when the same class’s internal methods are called.

What are the consequences of this:

1: For internal calls, the transaction declaration of the called method will have no effect

2: In other words, when you declare a method that requires a transaction, if the class has other developers, you can’t guarantee that the method will actually be in a transaction environment

3: In other words, Spring’s transaction propagation strategy will not work when internal method calls are made.

Whether you want a method to require a separate transaction, be it RequiresNew, Nested, Nested, etc., it doesn’t work.

4: Not just transactional advice, but any AOP advice you implement yourself with Spring will be subject to the same restrictions…

[out]

The cause of the problem has been found, in fact, my ideal AOP implementation, should be the following:


As long as a Cglib enhanced object is fine, for the Java proxy approach, MY choice is to abandon without hesitation.

As for the previous transaction problem, everything is fine as long as you avoid the limitations of Spring’s current AOP implementation and either declare transactions for both, split them into two classes, or use programmatic transactions directly in your methods.

The last

If you feel good, you can click a “like” under the concern, and we will share more articles in the future!