在 spring 中有条件地配置 transactionManager 时如何使用 Transactional 注释?

How to use Transactional annotation when config transactionManager conditionally in spring?

我在 spring 项目中使用多个数据源。 我 enable/disable 在项目启动时通过手动配置它们。 一次所有这些都可能处于活动状态 因此 transactionManager bean 可能处于活动状态或不处于活动状态。

我在spring配置class中通过@Conditional注解实现。 当我在方法上使用禁用事务注释时,我有 NoSuchBeanDefinitionException。

当我有条件地定义 transactionManager bean 时如何在方法上使用事务性注释?

archiveTransactionManager bean 不是由 @Conditional 注释创建的,我希望spring跳过检查条件事务管理器的 bean 验证。

对于条件 sessionFactory bean,我将 Autowired 注释中的 'required' 参数设置为 false 以防止 spring 抛出 NoSuchBeanDefinitionException 但我为 @Transactional 做了什么?

配置class

    @Bean("archiveTransactionManager")
    @Conditional(ArchiveCondition.class)
    public HibernateTransactionManager archiveTransactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(archiveSessionFactory());
        return transactionManager;
    }

交易方法

    @Transactional(value = "archiveTransactionManager", readOnly = true)
    private List<DocumentItem> loadArchivedDocumentItem() {...}

用法

if(GeneralSetting.isArchive)
   documentService.loadArchivedDocumentItem();

当前结果:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'archiveTransactionManager' available: No matching PlatformTransactionManager bean found for qualifier 'archiveTransactionManager' - neither qualifier match nor bean name match!

我希望spring在某些情况下跳过条件事务管理器 bean 的 bean 验证,这些情况它们不是由条件创建的 .

您使用了错误的注解来命名 bean。 @Qualifier 用于注入点指定名称。您需要使用 @Bean 为 bean 命名。所以你的 bean 定义需要像这样:

@Bean("archiveTransactionManager")
@Conditional(ArchiveCondition.class)
public HibernateTransactionManager archiveTransactionManager() {
  HibernateTransactionManager transactionManager = new HibernateTransactionManager();
  transactionManager.setSessionFactory(archiveSessionFactory());
  return transactionManager;
}

我会将其视为后备方案,您必须在失败后恢复。在这种情况下,有一个用

注释的方法调用方法

@Transactional(value = "archiveTransactionManager", readOnly = true)

在失败(或异常)的情况下,调用带有

注释的方法

@Transactional(value = "alternativeTransactionManager", readOnly = true)

public void doSomething() {
    try {
        tryFirst();
    } catch (Exception e) {
        tryAlternative();
    }
}

@Transactional(value = "archiveTransactionManager", readOnly = true)
public void tryFirst() {

}

@Transactional(value = "alternativeTransactionManager", readOnly = true)
public void tryAlternative() {

}

请记住,您必须同时声明它们。

我实现了一个 no-op SessionFactory 并在 spring 配置 class 中实例化它,每当 archive_mode 被禁用时:

SpringConfig.java

    @Bean("archiveSessionFactory")
    public SessionFactory archiveSessionFactory() {
        return ServerConf.ARCHIVE_MODE ? createNormalSessionFactory() : new DummySessionFactory();
    }

    @Bean("archiveTransactionManager")
    public HibernateTransactionManager archiveTransactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(archiveSessionFactory());
        return transactionManager;
    }

DummySessionFactory.java

public class DummySessionFactory implements SessionFactory {
...
    // These two methods call in spring initializing and we have to implement them
    @Override
    public Metamodel getMetamodel() {
       return new MetamodelImpl(null);
    }

    @Override
    public Map<String, Object> getProperties() {
       return null;
    }

    //Throw suitable exception in other methods
    @Override
    public Session getCurrentSession() throws HibernateException {
        throw new HibernateException("Desired mode is Disabled");
    }
...
}