Warm tip: This article is reproduced from serverfault.com, please click

java-为什么在我使用EnableTransactionManegment(mode = Advice.ASPECTJ)时 Spring 交易不起作用?

(java - Why spring transactions dont work when i use EnableTransactionManegment(mode=Advice.ASPECTJ)?)

发布于 2020-12-26 16:45:14

我尝试使用带有AspectJ的Spring事务

**我的项目: build.config

plugins {

    id 'org.springframework.boot' version '2.3.3.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    
    id "io.freefair.aspectj.post-compile-weaving" version "5.1.0"
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

project.ext {
    aspectjVersion = "1.8.2"
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework:spring-jdbc'
    implementation 'org.springframework:spring-tx'

    implementation 'org.postgresql:postgresql'

    implementation 'org.aspectj:aspectjrt'
    implementation 'org.aspectj:aspectjweaver'
    implementation 'org.aspectj:aspectjtools'
    implementation 'org.springframework:spring-aspects:5.3.2'
    implementation 'org.springframework:spring-instrument:5.3.2'

}

test {
    useJUnitPlatform()
}

DataConfig.class

   @Configuration
   @EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
   public class DataConfig {

     @Bean
     public DataSource postgres() {
         DriverManagerDataSource dataSource = new DriverManagerDataSource();
         dataSource.setDriverClassName("org.postgresql.Driver");
         dataSource.setUrl("jdbc:postgresql://localhost:5432/postgres?serverTimezone=UTC");
         dataSource.setUsername("postgres");
         dataSource.setPassword("admin");
         dataSource.setSchema("public");
         return dataSource;
     }

     @Bean
     public PlatformTransactionManager transactionManager() {
         return new DataSourceTransactionManager(postgres());
     }
  }

MainDAO类

@Repository
public class MainDAO {
    private final JdbcTemplate jdbcTemplate;
    

    public MainDAO(DataSource postgres) {
        this.jdbcTemplate = new JdbcTemplate(postgres);
    }

    public Integer getSoundsCount() {
        return jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM Sound", Integer.class);
    }


    @Transactional(propagation = Propagation.MANDATORY)
    public void insertSound() {
        insertAuthor();
        jdbcTemplate.update(
                "INSERT INTO Sound (author, name, id) VALUES (?,?,?)",
                0, "Spring", 0);
    }
}

当我从我的服务中调用方法insertSound时,它会毫无例外地运行。但是它应该抛出异常,因为方法insertSound具有传播性。

在此处输入图片说明

如果我将EnableTransactionManegment的Advice模式更改为mode = Advice.PROXY,则出现异常 在此处输入图片说明

但是,如果使用mode = Advice.ASPECTJ,交易将无法进行。

我也尝试运行带有批注EnableLoadTimeWeaving的应用程序,并将库spring-instrument设置为java代理,但它也无法进行交易:

在此处输入图片说明

在此处输入图片说明

我应该怎么做才能使交易与mode = Advice.ASPECTJ一起使用?

Questioner
tiger
Viewed
0
kriegaex 2020-12-30 22:36:25

加载时间编织(LTW)

为了使LTW能够正常工作,你可以-javaagent:path/to/aspectjweaver.jar在命令行上与组合使用-javaagent:path/to/spring-instrument.jar,也可以将@EnableLoadTimeWeaving之前提到的添加到你的配置中。

编译时编织(CTW)

我找到了一种使Spring的原生AspectJ声明式事务与编译时编织一起工作的方法,请参阅我的pull request其他细节之一是:

@Bean
public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(h2());
    // Make native AspectJ declarative transactions work with compile-time weaving
    AnnotationTransactionAspect.aspectOf().setTransactionManager(transactionManager);
    return transactionManager;
}

另请参阅此答案以供参考。

在之后正常运行应用程序时(即,-javaagent由于已经编译了事务方面而没有任何参数)mvn compile,控制台日志应在Native AspectJ active = true每次sounds/add调用URI时显示该日志行由我为说明而添加的以下调试语句触发:

@Transactional//(propagation = Propagation.MANDATORY)
public void insertSound() {
    boolean nativeAspectjActive = Arrays
        .stream(new Exception().getStackTrace())
        .map(StackTraceElement::toString)
        .anyMatch(signature -> signature.contains("MainDAO.insertSound_aroundBody"));
    logger.info("Native AspectJ active = " + nativeAspectjActive);
    // (...)
}