spring-projects / spring-projects/spring-framework

No well-defined advice order for @Transactional and @Async in AspectJ mode

Open
#24,309 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: data type: enhancement
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

Affects: 5.x.x


Since Spring 5 (spring-aspects 5.x.x), it looks like @Transactional is ignored on the method with @Async when using AdviceMode.ASPECTJ for both @EnableTransactionManagement and @EnableAsync.

Please take a look on following demo: https://github.com/kklepacz/spring-async-transaction-demo

After running mvn clean test you should see following output:

2020-01-07 12:02:50.729  INFO 29454 --- [ async-thread-1] c.e.asynctransactiondemo.AsyncListener   : Transaction in async listener? false

So even if @Transactional annotation is present on handle method, transaction is not active.

Now, let's change Spring version. Update pom to use Spring 4 + Spring Boot 1.5.x

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.22.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

Run mvn clean test again. Output:

2020-01-07 12:06:38.082 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.asynctransactiondemo.AsyncListener.handle]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2020-01-07 12:06:38.082 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3bcd99f8] for JPA transaction
2020-01-07 12:06:38.083 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@350a70f1]
2020-01-07 12:06:38.083  INFO 29675 --- [ async-thread-1] c.e.asynctransactiondemo.AsyncListener   : Transaction in async listener? true
2020-01-07 12:06:38.085 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2020-01-07 12:06:38.085 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3bcd99f8]
2020-01-07 12:06:38.085 DEBUG 29675 --- [ async-thread-1] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3bcd99f8] after transaction

Transaction is active.

Is it a bug or a feature and I need some extra configuration to have my Spring Boot 2 version working as expected?

Is it related to AJC compilation anyhow? I can see a difference between an order of compilation in maven output.
For Spring Aspects 5.x:

[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect' (spring-aspects-5.1.9.RELEASE.jar!AbstractAsyncExecutionAspect.class:65(from AbstractAsyncExecutionAspect.aj))
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (spring-aspects-5.1.9.RELEASE.jar!AbstractTransactionAspect.class:66(from AbstractTransactionAspect.aj))

For Spring Aspects 4.x - order is different:

[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (spring-aspects-4.3.25.RELEASE.jar!AbstractTransactionAspect.class:66(from AbstractTransactionAspect.aj))
[INFO] Join point 'method-execution(void com.example.asynctransactiondemo.AsyncListener.handle(com.example.asynctransactiondemo.SomeEntitySaved))' in Type 'com.example.asynctransactiondemo.AsyncListener' (AsyncListener.java:19) advised by around advice from 'org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect' (spring-aspects-4.3.25.RELEASE.jar!AbstractAsyncExecutionAspect.class:65(from AbstractAsyncExecutionAspect.aj))

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked async transaction demo and run mvn clean test to reproduce the missing transaction in Spring 5 with AdviceMode.ASPECTJ. Compare the Spring 4 and Spring 5 AJC advice-order output in the issue, then inspect the relevant spring-aspects transaction and async aspects. Done means the advice order is well-defined and the reported @Async method has the expected active transaction.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.