我正在使用 Spring boot 2.5.5 和 AspectJ 1.9.7 (CTW)。我发现有时事务不会回滚,要解决这个问题,我只需要重新编译代码并再次运行它。例如:
我有方法 addB() 持久化实体 B,方法 addC() 抛出异常,方法 A() 将它们组合起来。当我调用 A() 时,抛出异常,但实体 B 保留在数据库中(如预期)。当我用 @Transactional 注释方法 A() 时,结果是相同的。但是,如果我再次构建所有内容(没有任何更改),那么事务将被回滚,并且数据库中没有新记录。
这是我的完整 POM:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abcc</groupId>
<artifactId>abcc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>abcc</name>
<description>abcc</description>
<properties>
<java.version>11</java.version>
<log4j2.version>2.15.0</log4j2.version>
<aspectj.version>1.9.7</aspectj.version>
<aspectj-maven-plugin.version>1.14.0</aspectj-maven-plugin.version>
</properties>
<dependencies>
<!--SPRING-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--CACHE-->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>
<!--DATABASE-->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.1</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.19.Final</version>
</dependency>
<dependency>
<groupId>org.passay</groupId>
<artifactId>passay</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.sanctionco.jmail</groupId>
<artifactId>jmail</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.13</version>
</dependency>
<!--AOP-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>test</id>
<properties>
<activatedProperties>test</activatedProperties>
</properties>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
</dependency>
</dependencies>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>${aspectj-maven-plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<Xlint>ignore</Xlint>
<verbose>true</verbose>
<source>${java.version}</source>
<target>${java.version}</target>
<complianceLevel>${java.version}</complianceLevel>
<encoding>utf-8</encoding>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.outputDirectory}</weaveDirectory>
</weaveDirectories>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
这是非常奇怪的情况,我找不到相关信息。你能帮忙找出原因吗?
最佳答案
我无法重现该问题,因为 IDEA 找不到 Lombok setter。即使在运行之前将构建操作委托(delegate)给 Maven,我也会收到 NoSuchMethodError: '...TestEntity.setCode(java.lang.String)'
。接下来,我将尝试不使用 Lombok。请注意,Lombok 和 AspectJ 不能很好地配合,请参阅 my answer here 。或者,您还可以确保 Maven 执行以下任一操作:
- 首先使用 Javac + Lombok 进行构建,然后在第二步中应用 AspectJ 二进制编织,所有这些都在一个模块中。
- 与上面类似,但在模块 A 中执行第一个构建步骤,在单独的模块 B 中执行第二个构建步骤。然后您将获得一个未编织和一个编织的工件,您可以根据自己的喜好使用它们。例如,您还可以使用未编织的方式,并在启动应用程序时通过加载时编织 (LTW) 应用事务方面。请参阅my other answer here对于方法 #1 和方法 #2。
- Delombok 源代码在第二个构建步骤中使用 AspectJ 编译器构建生成的源代码。
我在 IDE 中生成了构造函数、getter 和 setter,而不是使用 Lombok。现在该项目可以在 IDE 和 Maven 中编译。它的行为完全符合预期。使用 @Transactional
会创建 0 个实体,没有 @Transactional 则创建 2 个实体。
我不确定 Lombok 与 AspectJ 是否真的是由于使用 Lombok 注释时的不可编译性而导致的问题,但对于您来说,在没有 Lombok 的情况下尝试应该很容易。如果它在您的环境中也有效,我们就找到了罪魁祸首,并且可以考虑实现上述 3 种方法之一。然后你可以告诉我如果你这样做有什么困难。
更新:我在我的 fork 中为您创建了两个模块版本 - Javac + Lombok,然后是 Aspect weaving,并且还发布了 pull request #1 。我还稍微提高了可测试性。看看这是否适合您。
警告:您不能简单地从 application-lombok
模块运行 DemoApplication
,因为该模块仍处于未编织状态,不会显示事务行为。但是您可以简单地将运行配置的类路径更改为 application-aspectj
模块:
更新:正如我们在另一个答案的评论部分中发现的那样,除了 Lombok 与 AspectJ 编译器配置有问题之外,OP 的 IDE 也有问题:使用 IntelliJ IDEA Community Edition,他首先不知道,然后无法安装 AspectJ 插件,这意味着 IDEA 不知道 AspectJ 编译器的任何信息,只是简单地用普通 Java 类覆盖了 AspectJ Maven 之前可能编译的任何内容。因此,事务方面也不起作用,除非
- 禁用预运行编译,并启动
mvncompile
作为相应运行配置的附加预构建步骤, - 或者项目的所有构建操作都通过配置委托(delegate)给 Maven,
- OP 购买 IDEA Ultimate 许可证并安装 AspectJ 插件。
关于Spring 方面由 AspectJ 编译器编织,可在 Maven 中工作,但不能在 IntelliJ IDEA 中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70436706/