简体   繁体   中英

Spring Transaction with mode = AdviceMode.ASPECTJ doesn't work correctly

I know that spring transaction works with mode = AdviceMode.PROXY by default, but we haven't opportunity open new transaction inside one service. This problem is fixed with mode = AdviceMode.ASPECTJ. But my code isn't work correctly with this attributes.

Config:

@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@EnableJpaRepositories(
        entityManagerFactoryRef = "mysqlEntityManagerFactory",
        transactionManagerRef = "mysqlTransactionManager",
        basePackages = {"softserve.spring.com.repository"}
)
public class TransactionConfig {

    @Bean(name = "mysqlDataSource")
    @ConfigurationProperties(prefix = "mysql.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder
                .create()
                .build();
    }

    @Bean(name = "mysqlEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("mysqlDataSource") DataSource dataSource
    ) {
        return builder
                .dataSource(dataSource)
                .packages("softserve.spring.com.entity")
                .persistenceUnit("mysql")
                .build();
    }

    @Bean(name = "mysqlTransactionManager")
    public PlatformTransactionManager mysqlTransactionManager(
            @Qualifier("mysqlEntityManagerFactory") EntityManagerFactory mysqlEntityManagerFactory
    ) {
        return new JpaTransactionManager(mysqlEntityManagerFactory);
    }

}

properties:

spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=false

mysql.datasource.jdbc-url=jdbc:mysql://localhost:3306/db_transaction?useSSL=false&useUnicode=yes&characterEncoding=UTF-8
mysql.datasource.username=root
mysql.datasource.password=root
mysql.datasource.driver-class-name=com.mysql.jdbc.Driver

service:

@Service
public class UserService {

    @Autowired
    private UserRepository userrepository;

    @Transactional
    public void createUsers() {
        create();

        User user = new User("B", 0);
        userrepository.save(user);

        throw new RuntimeException();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void create() {
        User user = new User("A", 100);
        userrepository.save(user);
    }

    @Transactional
    public void deleteAll() {
        userrepository.deleteAll();
    }

}

After the execution of this code in the database have to be one user. But I have two. How to set up correctly?

When using proxies, you have to be aware of what happens (and what doesn't) when you invoke methods on this , like you do with create() . Read the documentation to learn why this is not a transaction-handling bean:

However, once the call has finally reached the target object (the SimplePojo, reference in this case), any method calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the this reference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.

When using AspectJ, however, the very bytecode of your class is woven with the transaction-handling aspect, so even calls to this do work as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM