【问题标题】:Axon Aggregate Identifier Type Converter轴突聚合标识符类型转换器
【发布时间】:2020-12-12 02:55:00
【问题描述】:

问题:在聚合状态 Axon SpringBoot 应用程序中,@AggregateIdentifier 的类型为 UUID,而 PostgreSQL 数据库列的类型为 UUID。当在 create-commands 上持久化时 - 标识符已成功存储。当发送更新命令警告上升并且命令未传递到聚合处理程序时,因为@TargetAggregateIdentifier 需要字符串类型as described by Axon here

java.lang.IllegalArgumentException:为 类 ....MyAggregate。预期:类 java.util.UUID,得到类 java.lang.String

研究:

  1. 工作解决方案是将域重构为所有聚合标识符的String 类型。数据库@Id 字段也应转换为varchar(36) 类型以存储UUID.toString() 作为主键。主要的缺点是效率低下:9 倍的大小和更慢的字符串读取。

  2. 最小样板和折衷解决方案是将所有聚合标识符的域重构为 String 类型,并使用 javax.persistence.Converters 在 JPA 层中将 String 转换为 UUID,同时保持:​​

    @Converter
    public class UuidJpaConverter implements AttributeConverter<String, UUID> {
    
      @Override
      public UUID convertToDatabaseColumn(String uuid) {
        return fromString(uuid);
      }
    
      @Override
      public String convertToEntityAttribute(UUID uuid) {
        return uuid.toString();
      }
    }
    
    ...
    
    @Aggregate
    @Entity
    @IdClass(UuidKey.class)
    public class MyAggregate implements Serializable {
    
      @AggregateIdentifier
      @Id
      private String uuid;
      ...
    }
    
    public class UuidKey implements Serializable {
    
      @Column(name = "uuid", nullable = false, updatable = false)
      @Convert(converter = UuidJpaConverter.class)
      private String uuid;
    }
    

但结果是:

o.h.engine.jdbc.spi.SqlExceptionHelper:错误:列“uuid”的类型为 uuid,但表达式的类型为 bytea

  1. 使用 Axon 标识符转换器,但它需要为每个聚合自定义 GenericJpaRepository,实际上从不在断点上调用 identifierConverter 处理程序:

     @Configuration
     public class IdentifierConverter {
    
       @Bean
       public GenericJpaRepository<MyAggregate> aggregateJpaRepository(
           EntityManagerProvider provider,
           @Qualifier("eventBus") EventBus simpleEventBus) {
    
         GenericJpaRepository<MyAggregate> repository = GenericJpaRepository
             .builder(MyAggregate.class)
      ->       .identifierConverter(name -> UUID.fromString(name))
             .entityManagerProvider(provider)
             .eventBus(simpleEventBus)
             .build();
    
         return repository;
       }
     }
    

结果:

o.h.engine.jdbc.spi.SqlExceptionHelper:错误:列“uuid”属于 输入 uuid,但表达式的类型是不同的字符

  1. 还有一个suggested universal GenericJpaRepository solution 来查找聚合标识符的类型,并且 - 除非它已经是一个字符串 - 通过 Spring 转换服务对其进行转换。但是当我们有 Axon 自动配置并且期望 bean 支持 Configurer 时,不清楚在哪里绑定它会将它添加到配置器中的 registerAggregateBeanDefinitions

     final Class<?> aggregateIdentifierType = Stream.of( aggregateType.getDeclaredFields( ) )
     .filter( field -> field.isAnnotationPresent( AggregateIdentifier.class ) )
     .map( field -> field.getType( ) )
     .findFirst( )
     .orElseThrow( ( ) -> new IllegalStateException( "The aggregate '" + aggregate + "' does not have an identifier." ) );
    
     aggregateConf.configureRepository(
     c -> GenericJpaRepository.builder( aggregateType )
             .identifierConverter( string -> {
                 if ( aggregateType == String.class ) {
                     return string;
                 } else {
                     try {
                         final ConversionService conversionService = beanFactory.getBean( ConversionService.class );
                         return conversionService.convert( string, aggregateIdentifierType );
                     } catch ( final NoSuchBeanDefinitionException ex ) {
                         throw new IllegalStateException( "Unable to convert String to aggregate identifier of type '" + aggregateIdentifierType.getName( ) + "'. A conversion service is missing." );
                     }
                 }
             } )
    
     ...
    
     @Named
     final class MyIdConverter implements Converter<String, MyId> {
    
         ...
    
         @Override
         public MyId convert( final String source ) {
             return MyId.fromString( source );
         }
    
     }
    

问题:如何在 PostgreSQL 数据库中保留 UUID 类型的聚合标识符 - 将 UUID 作为 @AggregateIdentifier 或至少 String 的首选类型。另外,如果at 2010 UUID was widely used in Axon,为什么目前只支持String

【问题讨论】:

    标签: java postgresql spring-boot jpa axon


    【解决方案1】:

    老实说,@Zon 在这里你已经深入探讨了这个问题。不确定我是否可以为您提供足够的帮助,但无论如何我都会尝试。

    研究点 1 显然是让事情立即发挥作用的最实用的解决方案。如果您要注意到StringUUID 相比的“效率低下”,我会感到很难受。因此,如果这是绝对否决,则应继续进行调查。否则,它当然可以完成工作。

    当谈到研究点 2 和 3 时,我相信您遇到了用于 PostgreSQL 的方言的问题,尽管我在这里不是 100% 确定。尤其是 PostgreSQL 有几个“很棒”的类型,但它们并不总是在所有场景中自动工作。我在这里的“猜测”是基于强制 PostgreSQL 使用 BYTEA 而不是 OID,以防你想降低 Postgres 的 TOAST 功能。如果您选择将 Postgres 用于事件存储并希望能够实际查看事件的内容,这将变得特别方便。例如,此博客文章指定了如何处理此问题。更重要的是,这篇blog 帖子展示了如何调整所使用的方言。也许这可以在解决方案 2 和 3 中为您服务?

    在这种情况下,选项 4 应该是最合乎逻辑的解决方案。但我从你的回复中得知,你目前没有让它工作。当将 Axon 与 Spring 结合使用时,SpringAxonAutoConfigurer(我相信您指的是 registerAggregateBeanDefinitions 方法)将自动检查您的 Aggregate 上的可配置 bean。它基于@Aggregate 中定义的字段(即 Axon 的 Spring 原型注释)来执行此操作。更具体地说,您可以使用@Aggregate 中的repository 字段来定义要使用的存储库的bean 名称。

    因此,您应该能够简单地为GenericJpaRepository bean 提供所需的identifierConverter。该 bean 的名称可以在 MyAggregate 上的 @Aggregate 注释中指定,以便 Axon 的自动配置可以正确选择它。希望对您有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多