简体   繁体   English

当@ActiveProfiles(“test”)时,如何忽略特定方法的spring @Transactional注释

[英]How can I ignore spring @Transactional annotation for a specific method when @ActiveProfiles(“test”)

I need to ignore the following @Transactional annotation during my integration tests. 在集成测试期间,我需要忽略以下@Transactional注释。

@Service
public class MyClass {

    @Transactional(propagation = Propagation.NEVER)
    public void doSomething() {
        // do something that once in production can not be inside a transaction (reasons are omitted)
    }

}

The problem is that all my tests are executed inside a transaction that is rolled back by default. 问题是我的所有测试都是在默认情况下回滚的事务中执行的。 How could I ignore the @Transactional(propagation = Propagation.NEVER) annotation for this method when it is running in the scope of a test ( @ActiveProfiles("test") ) allowing it to be executed inside a transaction? 当该方法在测试范围内运行时( @ActiveProfiles("test") )允许它在事务内执行时,我怎么能忽略该方法的@Transactional(propagation = Propagation.NEVER)注释?

First of all, you need to exclude your current @EnableTransactionManagement annotation to be active in your test profile. 首先,您需要将当前的@EnableTransactionManagement注释排除在test配置文件中。 You can do this by isolating the @EnableTransactionManagement annotation to a separate configuration class which excludes the profile test so it only gets activated whenever the test profile is not active. 您可以通过将@EnableTransactionManagement批注隔离到单独的配置类来完成此操作,该配置类排除了配置文件test因此只有在test配置文件活动时才会激活它。

@EnableTransactionManagement(mode=AdviceMode.PROXY)
@Profile("!test")
public class TransactionManagementConfig {}

With that in place, we can start building up the custom transaction management configuration for your test profile. 有了这些,我们就可以开始为您的测试配置文件构建自定义事务管理配置。 First we define an annotation that will be used to activate custom transaction management (javadoc comments stripped for compactness of the example, see EnableTransactionManagement javadoc for details). 首先,我们定义一个将用于激活自定义事务管理的注释(为示例的紧凑性剥离javadoc注释,有关详细信息,请参阅EnableTransactionManagement javadoc)。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CustomTransactionManagementConfigurationSelector.class)
public @interface EnableCustomTransactionManagement {
    boolean proxyTargetClass() default false;
    AdviceMode mode() default AdviceMode.PROXY;
    int order() default Ordered.LOWEST_PRECEDENCE;
}

Then we need an import selector. 然后我们需要一个导入选择器。 Note, that since you're using AdviceMode.PROXY , i skipped implementing the ASPECTJ part, but that should be done analogously in order to use AspectJ based transaction management. 请注意,由于您正在使用AdviceMode.PROXY ,我跳过了实现ASPECTJ部分,但这应该类似地完成,以便使用基于AspectJ的事务管理。

public class CustomTransactionManagementConfigurationSelector extends
        AdviceModeImportSelector<EnableCustomTransactionManagement> {
    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
        case PROXY:
            return new String[] { 
                AutoProxyRegistrar.class.getName(),
                CustomTransactionAttributeSourceConfig.class.getName()
            };
        case ASPECTJ:
        default:
            return null;
        }
    }
}

And finally the part where you will be able to override the transaction attributes. 最后,您将能够覆盖事务属性的部分。 This one subclasses ProxyTransactionManagementConfiguration for AdviceMode.PROXY , you would need an analogous implementation based on AspectJTransactionManagementConfiguration for AdviceMode.ASPECTJ . 这一个子类ProxyTransactionManagementConfigurationAdviceMode.PROXY ,则需要基于类似的实现AspectJTransactionManagementConfigurationAdviceMode.ASPECTJ Feel free to implement your own logic, whether be it a constant override of whatever attributes the original AnnotationTransactionAttributeSource would determine as in my example, or going to greater lengths by introducing and handling your own custom annotation for this purpose. 随意实现您自己的逻辑,无论是原始AnnotationTransactionAttributeSource将在我的示例中确定的任何属性的常量覆盖,还是通过为此目的引入和处理您自己的自定义注释来实现更大的长度。

@Configuration
public class CustomTransactionAttributeSourceConfig
        extends ProxyTransactionManagementConfiguration {

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        this.enableTx = AnnotationAttributes
                .fromMap(importMetadata.getAnnotationAttributes(
                        EnableCustomTransactionManagement.class.getName(),
                        false));
        Assert.notNull(this.enableTx,
                "@EnableCustomTransactionManagement is not present on importing class "
                        + importMetadata.getClassName());
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Override
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource() {

            private static final long serialVersionUID = 1L;

            @Override
            protected TransactionAttribute findTransactionAttribute(
                    Class<?> clazz) {
                TransactionAttribute transactionAttribute = 
                        super.findTransactionAttribute(clazz);
                if (transactionAttribute != null) {
                    // implement whatever logic to override transaction attributes 
                    // extracted from @Transactional annotation
                    transactionAttribute = new DefaultTransactionAttribute(
                            TransactionAttribute.PROPAGATION_REQUIRED);
                }
                return transactionAttribute;
            }

            @Override
            protected TransactionAttribute findTransactionAttribute(
                    Method method) {
                TransactionAttribute transactionAttribute = 
                        super.findTransactionAttribute(method);
                if (transactionAttribute != null) {
                    // implement whatever logic to override transaction attributes
                    // extracted from @Transactional annotation
                    transactionAttribute = new DefaultTransactionAttribute(
                            TransactionAttribute.PROPAGATION_REQUIRED);
                }
                return transactionAttribute;
            }
        };
    }
}

Finally, you'll need to enable the custom transaction management configuration with a configuration class tied to the test profile. 最后,您需要使用与test配置文件绑定的配置类启用自定义事务管理配置。

@EnableCustomTransactionManagement(mode=AdviceMode.PROXY)
@Profile("test")
public class TransactionManagementTestConfig {}

I hope this helps. 我希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 @Transactional 注释测试方法 - How test a method with @Transactional annotation Spring 测试中的@Transactional 注解 - @Transactional annotation in Spring Test 春季测试事务注释不起作用 - Spring Test Transactional annotation not working 如何配置 JUnit 以仅在测试方法中忽略 @Before 注释 - How can I configure JUnit to ignore @Before annotation only in a Test method Spring @Transactional Annotation类或方法 - Spring @Transactional Annotation class or method spring + hiberante:如何判断spring是否已拾取所有@transactional批注 - spring+hiberante: how can I tell if spring has picked up all the @transactional annotation 调用@Transactional带注释的方法时,如何以编程方式提供特定的事务管理器 - How can I programatically provide a specific transaction manager when calling a @Transactional annotated method 使 spring 测试方法不是事务性的 - make spring test method NOT transactional 关于方法的Spring @Transactional注释的一些说明 - Some clarification about Spring @Transactional annotation on a method 如果我在配置 class 上使用 @ActiveProfiles 注释而不是在定义我的 bean 的 class 上使用它,Spring 会发生什么? - What happens in Spring if I use the @ActiveProfiles annotation on a configuration class instead use it on the class that defines my beans?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM