【问题标题】:Why spring transactions dont work when i use EnableTransactionManegment(mode=Advice.ASPECTJ)?为什么当我使用 EnableTransactionManagement(mode=Advice.ASPECTJ) 时 spring 事务不起作用?
【发布时间】: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.class

@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 有 propogation.MANDATORY。

如果我将 EnableTransactionManegment 的 Advice 模式更改为 mode=Advice.PROXY 那么我会得到异常

但是使用 mode=Advice.ASPECTJ,事务不起作用。

我还尝试使用注释 EnableLoadTimeWeaving 运行应用程序并将库 spring-instrument 设置为 java 代理,但它也无法使用事务:

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

【问题讨论】:

    标签: java spring-boot transactions aop aspectj


    【解决方案1】:

    加载时编织 (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;
    }
    

    参见this answer

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

    @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);
        // (...)
    }
    

    【讨论】:

    • 感谢您找到了一种使 Spring 的原生 AspectJ 声明式事务与编译时编织一起工作的方法!
    • 我有一些空闲,很好奇,否则我不会打扰。我不正常使用Spring。
    猜你喜欢
    • 2017-02-26
    • 1970-01-01
    • 2011-01-21
    • 2021-07-06
    • 1970-01-01
    • 2016-08-21
    • 2021-11-10
    • 1970-01-01
    • 2014-11-29
    相关资源
    最近更新 更多