
Co-authored-by: Dorian Burihabwa <75226315+dorian-burihabwa-sonarsource@users.noreply.github.com>
161 lines
5.0 KiB
Plaintext
161 lines
5.0 KiB
Plaintext
== Why is this an issue?
|
|
|
|
Transactional methods have a propagation type parameter in the @Transaction annotation that specifies the requirements about the transactional context in which the method can be called and how it creates, appends, or suspends an ongoing transaction.
|
|
|
|
When an instance that contains transactional methods is injected, Spring uses proxy objects to wrap these methods with the actual transaction code.
|
|
|
|
However, if a transactional method is called from another method in the same class, the `this` argument is used as the receiver instance instead of the injected proxy object, which bypasses the wrapper code.
|
|
This results in specific transitions from one transactional method to another, which are not allowed:
|
|
|
|
[frame=all]
|
|
[cols="^1,^1"]
|
|
|===
|
|
|From|To
|
|
|
|
| non-``++@Transactional++`` | MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
|
|
| MANDATORY | NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
|
|
| NESTED | NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
|
|
| NEVER | MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
|
|
| NOT_SUPPORTED | MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
|
|
| REQUIRED or ``++@Transactional++`` | NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
|
|
| REQUIRES_NEW | NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
|
|
| SUPPORTS | MANDATORY, NESTED, NEVER, NOT_SUPPORTED, REQUIRED, REQUIRES_NEW
|
|
|===
|
|
|
|
== How to fix it
|
|
|
|
Change the corresponding functions into a compatible propagation type.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
public void doTheThing() {
|
|
// ...
|
|
actuallyDoTheThing(); // Noncompliant, call from non-transactional to transactional
|
|
}
|
|
|
|
@Transactional
|
|
public void actuallyDoTheThing() {
|
|
// ...
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,java,diff-id=1,diff-type=compliant]
|
|
----
|
|
@Transactional
|
|
public void doTheThing() {
|
|
// ...
|
|
actuallyDoTheThing(); // Compliant
|
|
}
|
|
|
|
@Transactional
|
|
public void actuallyDoTheThing() {
|
|
// ...
|
|
}
|
|
----
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
@Transactional
|
|
public void doTheThing() {
|
|
// ...
|
|
actuallyDoTheThing(); // Noncompliant, call from REQUIRED to REQUIRES_NEW
|
|
}
|
|
|
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
public void actuallyDoTheThing() {
|
|
// ...
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,java,diff-id=2,diff-type=compliant]
|
|
----
|
|
@Transactional
|
|
public void doTheThing() {
|
|
// ...
|
|
actuallyDoTheThing(); // Compliant, call from REQUIRED to MANDATORY
|
|
}
|
|
|
|
@Transactional(propagation = Propagation.MANDATORY)
|
|
public void actuallyDoTheThing() {
|
|
// ...
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html[Spring Framework 6 API: Enum Class propagation]
|
|
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html[Spring Framework 6 API: Annotation Interface Transactional]
|
|
- https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/tx-propagation.html[Spring 6 Documentation: Transaction Propagation]
|
|
|
|
=== Articles & blog posts
|
|
|
|
- https://www.baeldung.com/spring-transactional-propagation-isolation[Baeldung: Transaction Propagation and Isolation in Spring @Transactional]
|
|
- https://dzone.com/articles/spring-transaction-propagation[DZone: Spring Transaction Propagation in a Nutshell]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
"xxx's" @Transactional requirement is incompatible with the one for this method.
|
|
|
|
|
|
=== Highlighting
|
|
|
|
* primary: method call
|
|
* secondary:
|
|
** calling method's ``++@Transactional++`` annotation or, if none, calling method signature.
|
|
** called method's ``++@Transactional++`` annotation or signature
|
|
** message: "Incompatible method definition."
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 21 Nov 2014, 12:29:50 Freddy Mallet wrote:
|
|
I would tag this rule with the label "spring"
|
|
|
|
=== on 20 Jun 2018, 14:39:00 Alban Auzeill wrote:
|
|
@Ann I don't understand why there's a difference between ``++@Transactional++`` and ``++@Transactional(propagation = Propagation.REQUIRED)++`` (the default) ?
|
|
|
|
And I disagree with incompatible propagations list, this is my proposal:
|
|
|
|
||From||To||
|
|
|
|
| non-``++@Transactional++`` | MANDATORY, REQUIRED, REQUIRES_NEW |
|
|
|
|
| MANDATORY | NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW |
|
|
|
|
| NESTED | MANDATORY, NESTED, NEVER, NOT_SUPPORTED, REQUIRED, REQUIRES_NEW |
|
|
|
|
| NEVER | MANDATORY, REQUIRED, REQUIRES_NEW |
|
|
|
|
| NOT_SUPPORTED | MANDATORY, REQUIRED, REQUIRES_NEW |
|
|
|
|
| REQUIRED or ``++@Transactional++`` | NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW |
|
|
|
|
| REQUIRES_NEW | NESTED, NEVER, NOT_SUPPORTED REQUIRES_NEW |
|
|
|
|
| SUPPORTS | MANDATORY, NESTED, NEVER, NOT_SUPPORTED, REQUIRED, REQUIRES_NEW |
|
|
|
|
|
|
javadoc https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html[org.springframework.transaction.annotation.Propagation]
|
|
|
|
javadoc https://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.html[javax.transaction.Transactional]
|
|
|
|
endif::env-github,rspecator-view[]
|