【问题标题】:Axon Framework: how to configure mutiple databases?Axon Framework:如何配置多个数据库?
【发布时间】:2020-05-18 13:27:28
【问题描述】:

我使用 mysql 作为事件存储,因此 axon-server-connector 被排除在类路径之外。我的用例描述如下。

  1. Spring Boot 2.1.7.RELEASE 和 axon 4.3.2
  2. 我打算有三个数据库,分别用于轴突事件存储、投影写入和投影读取。
@Configuration
public class DataSourceConfiguration {
    @Primary
    @Bean("axonMaster")
    @ConfigurationProperties("spring.datasource.hikari.axon-master")
    public DataSource axon() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean("projectionRead")
    @ConfigurationProperties("spring.datasource.hikari.projection-write")
    public DataSource master() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean("projectionWrite")
    @ConfigurationProperties("spring.datasource.hikari.projection-read")
    public DataSource slave() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }
}
  1. 我尝试使用 spring data jpa 配置多个数据源。主要的如下所示。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "axonEntityManagerFactory",
        basePackages = "org.axonframework.eventsourcing.eventstore.jpa") // (1)
public class AxonEventStoreConfig {
    @Primary
    @Bean(name="axonEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder, @Qualifier("axonMaster") DataSource axonMaster) {
        return builder
                .dataSource(axonMaster)
                .packages("org.axonframework.eventsourcing.eventstore.jpa")
                .persistenceUnit("axonMaster") //(2)
                .build();
    }

    @Primary
    @Bean(name = "axonPlatformTransactionManager") //(3)
    public PlatformTransactionManager transactionManager(
            @Qualifier("axonEntityManagerFactory") EntityManagerFactory axonEntityManagerFactory) {
        return new JpaTransactionManager(axonEntityManagerFactory);
    }
}

关于这部分的问题是:
(1)将basePackages设置为org.axonframework.eventsourcing.eventstore.jpa就够了吗?也许我还需要添加令牌包 org.axonframework.eventhandling.tokenstore.jpa 和 soga 包?我将使用 soga 商店。
(2) 这里的包和上一个包是一样的吗? persistenceUnit 的名称应该是什么?

示例项目上传到github:https://github.com/sincosmos/axon-multiple-databases
我无法运行应用程序。 我做的一切都正确吗?我参考了https://github.com/AxonIQ/giftcard-demo的例子,但是多数据库版本是基于axon 2.0,也需要配置axon command bus。

目标似乎很简单,在 axon 框架应用程序中配置多个数据库(一个用于事件存储),但即使我花了几天时间,我仍然一无所获。

谁能给我一些建议或帮助?我将不胜感激。

/****************************更新20200521 **************** ************/

我在阅读 Allard 的答案后取得了进步,现在我可以为应用程序配置多个数据库。源码上传到githubhttps://github.com/sincosmos/axon-multiple-databases.git

特别是对于axon event store,db配置如下图所示。

@Configuration
@EnableTransactionManagement
public class AxonEventStoreConfig {
    @Bean("axonMaster")
    @ConfigurationProperties("spring.datasource.hikari.axon-master")
    public DataSource axon() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean(name="axonEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder, @Qualifier("axonMaster") DataSource axonMaster) {
        return builder
                .dataSource(axonMaster)
                .persistenceUnit("axonMaster")
                .properties(jpaProperties())
                .packages("org.axonframework.eventhandling.tokenstore",
                        "org.axonframework.modelling.saga.repository.jpa",
                        "org.axonframework.eventsourcing.eventstore.jpa")
                .build();
    }

    /**
     * Is it right to provide EntityManagerProvider like this ???  
     * For axon event store
     * @param entityManagerFactory
     * @return
     */
    @Bean
    public EntityManagerProvider entityManagerProvider(@Qualifier("axonEntityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
        return () -> entityManagerFactory.getObject().createEntityManager();
    }

    private Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());
        props.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
        props.put("hibernate.hbm2ddl.auto", "update");
        props.put("hibernate.show_sql", "true");
        return props;
    }
}

在我启动应用程序后(如果是第一次,将自动创建事件存储相关表),轴突的数据库连接池很快就会耗尽。日志已粘贴供您参考。

Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
Hibernate: select min(domaineven0_.global_index)-1 as col_0_0_ from domain_event_entry domaineven0_
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
19:59:57.223 [EventProcessor[com.baeldung.axon.querymodel]-0] WARN  o.a.e.TrackingEventProcessor - Fetch Segments for Processor 'com.baeldung.axon.querymodel' failed: no transaction is in progress. Preparing for retry in 1s
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
Hibernate: select min(domaineven0_.global_index)-1 as col_0_0_ from domain_event_entry domaineven0_
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
19:59:58.293 [EventProcessor[com.baeldung.axon.querymodel]-0] WARN  o.a.e.TrackingEventProcessor - Fetch Segments for Processor 'com.baeldung.axon.querymodel' failed: no transaction is in progress. Preparing for retry in 2s
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
Hibernate: select min(domaineven0_.global_index)-1 as col_0_0_ from domain_event_entry domaineven0_
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
20:00:00.361 [EventProcessor[com.baeldung.axon.querymodel]-0] WARN  o.a.e.TrackingEventProcessor - Fetch Segments for Processor 'com.baeldung.axon.querymodel' failed: no transaction is in progress. Preparing for retry in 4s
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
Hibernate: select min(domaineven0_.global_index)-1 as col_0_0_ from domain_event_entry domaineven0_
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
20:00:04.465 [EventProcessor[com.baeldung.axon.querymodel]-0] WARN  o.a.e.TrackingEventProcessor - Fetch Segments for Processor 'com.baeldung.axon.querymodel' failed: no transaction is in progress. Preparing for retry in 8s
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
Hibernate: select min(domaineven0_.global_index)-1 as col_0_0_ from domain_event_entry domaineven0_
Hibernate: select tokenentry0_.segment as col_0_0_ from token_entry tokenentry0_ where tokenentry0_.processor_name=? order by tokenentry0_.segment ASC
20:00:12.531 [EventProcessor[com.baeldung.axon.querymodel]-0] WARN  o.a.e.TrackingEventProcessor - Fetch Segments for Processor 'com.baeldung.axon.querymodel' failed: no transaction is in progress. Preparing for retry in 16s
20:00:17.327 [HikariPool-1 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Pool stats (total=15, active=15, idle=0, waiting=0)
20:00:22.178 [HikariPool-2 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-2 - Pool stats (total=10, active=0, idle=10, waiting=0)
20:00:23.092 [HikariPool-3 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-3 - Pool stats (total=10, active=0, idle=10, waiting=0)

当我在 mysql 工作台中检查连接状态时,这些连接的状态为“睡眠”。更改连接池大小没有帮助。我还检查了jvm的堆栈,没有发现死锁。我将数据源泄漏检测阈值设置为 10000,但您可以看到没有打印数据源泄漏信息。 你能帮忙吗?

/****************************更新20200522 **************** ************/

事实证明“javax.persistence.TransactionRequiredException:没有事务正在进行中”是在事件处理器尝试访问 mysql 事件存储时发生的。我为每个数据源配置了事务管理器,但错误仍然存​​在。不知道发生了什么...

【问题讨论】:

  • 如果您的设置中有 org.axonframework.common.transaction.TransactionManager bean,可能值得验证。当您使用 spring 时,采用 SpringTransactionManager(包装 Spring 的 PlatformTransactionManager)将是最佳选择。这一切都应该是自动配置的,但是当您遇到事务问题时......
  • 谢谢史蒂文。我决定先开发业务逻辑。如果我以后能解决问题,我会更新帖子。
  • 这完全有道理@sincosmos。希望它会在这个过程中得到解决,如果没有,我们会在适当的时候注意到问题更新。祝你好运!

标签: spring-data-jpa event-sourcing axon


【解决方案1】:

当使用多个数据库时,您可能无法再依赖自动配置,因为 Spring 和 Axon 不知道您想使用这两个数据库中的哪一个。

Axon 不直接使用 EntityManager。相反,所有组件都需要一个 EntityManagerProvider。您也许可以利用它来发挥自己的优势。

如果您希望所有 Axon 组件都使用某个数据库,只需定义一个 EntityManagerProvider bean,该 bean 返回连接到该数据库的 EntityManager。 Spring 完全管理 EntityManager,因此您的所有 EntityManager 会话只需要一个实例。

如果您希望不同的组件使用不同的 EntityManager(例如,一个数据库中的 Event Store,另一个数据库中的 Token 和 Sagas),那么您需要自己配置这些组件。有时,从 AutoConfiguration 类中复制 bean 定义并调整它们以满足您的需求是最简单的。见https://github.com/AxonFramework/AxonFramework/tree/master/spring-boot-autoconfigure/src/main/java/org/axonframework/springboot/autoconfig

最后,您需要扫描的实体取决于您希望使用的组件。 Spring Boot 自动配置默认会扫描以下 Axon 包(如果你自己没有指定任何@EntityScan):

  • org.axonframework.eventhandling.tokenstore(用于令牌)
  • org.axonframework.modelling.saga.repository.jpa(用于 saga)
  • org.axonframework.eventsourcing.eventstore.jpa(用于事件存储)

注意@EnableJpaRepositories 注解用于扫描@Repository 类。 Axon 不使用这些,因此没有必要为它们扫描 Axon 包。 Axon 确实定义了实体,所以@EntityScan 会有意义。

【讨论】:

  • 感谢您的回复,实际上我阅读了很多与轴突框架和事件源相关的答案,所有这些答案都对我有很大帮助。阅读此答案后,一些困惑得到了缓解,但我仍然无法立即开始编写示例。例如,您提到“当使用多个数据库时,自动配置可能不可用”,您是说我将通过使用@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) 注释应用程序来排除数据源自动配置,否则轴突自动配置将不可用?
  • 无论如何,我最好根据您的回答进行更多研究。但我确实有很多困惑。你在github上有一个例子吗?我进行了搜索,但只找到了一个基于 axon 2.0 的多个数据库示例
  • 不,我的意思是 AutoConfiguration 不会总是为您创建所有 bean,因为它不知道应该使用哪个可用的数据源。为什么不使用 AxonServer 进行事件存储和消息传递?那是你为自己省去了很多麻烦。
  • 我们决定使用 mysql 作为事件存储,只是因为我们公司有一个 DBA 团队。通过听取您的建议,我取得了进展,但在主要问题部分进行编辑时遇到了另一个问题。你能给我一些建议吗?
  • 可能对您的团队和 DBA 团队有好处,您必须查看有关 Event Stores 的视频 -> youtube.com/watch?v=342tqAORbAM
猜你喜欢
  • 1970-01-01
  • 2013-12-16
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-22
相关资源
最近更新 更多