Axon MongoDB - message='E11000 重复键错误集合 uniqueAggregateIndex dup key: { : "101", : 0 }

Axon MongoDB - message='E11000 duplicate key error collection uniqueAggregateIndex dup key: { : "101", : 0 }

在我的应用程序中,我们使用 axon 3.3.3 和 mongo 数据库作为事件存储

每当用户更新其个人资料信息时,我们都会保存所有事件。

以下是用例

  1. 用户已创建个人资料(聚合 ID:101) 在 mongodb(CreateEvent) 中保存了 101 聚合 ID。
  2. 用户更新了个人资料, 所以我们想将 UpdateEvent 存储在 mongo db(event store)

    但低于异常

    13:52:49.643 [http-nio-7030-exec-3] 错误 o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet]在路径 [] 的上下文中抛出异常 [请求处理失败;嵌套异常是 org.axonframework.commandhandling.model.ConcurrencyException:序列 [0] 处的聚合 [101] 的事件已插入] 具有根本原因 com.mongodb.MongoBulkWriteException: 服务器 127.0.0.1:27017 上的批量写入操作错误。写入错误:[BulkWriteError{index=0, code=11000, message='E11000 duplicate key error collection: mytest.domainevents index: uniqueAggregateIndex dup key: { : "101", : 0 }', details={ }}]。 在 com.mongodb.connection.BulkWriteBatchCombiner.getError(BulkWriteBatchCombiner.java:176) 在 com.mongodb.connection.BulkWriteBatchCombiner.throwOnError(BulkWriteBatchCombiner.java:205) 在 com.mongodb.connection.BulkWriteBatchCombiner.getResult(BulkWriteBatchCombiner.java:146) 在 com.mongodb.operation.BulkWriteBatch.getResult(BulkWriteBatch.java:227) 在 com.mongodb.operation.MixedBulkWriteOperation.executeBulkWriteBatch(MixedBulkWriteOperation.java:276)

那么如何保存更新的事件?

下面是 mongo db

中的 uniqueAggregateIndex

{ "aggregateIdentifier" : 1, "sequenceNumber":1 }

@Value("${mongo.host:127.0.0.1}")
private String mongoHost;

@Value("${mongo.port:27017}")
private int mongoPort;

@Value("${mongo.db:mytest}")
private String mongoDB;

@Bean
public MongoSagaStore sagaStore() {
    return new MongoSagaStore(axonMongoTemplate());
}

@Bean
public TokenStore tokenStore(Serializer serializer) {
    return new MongoTokenStore(axonMongoTemplate(), serializer);
}

@Bean
public EventStorageEngine eventStorageEngine(Serializer serializer) {
    return new MongoEventStorageEngine(serializer, null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
}

@Bean
public MongoTemplate axonMongoTemplate() {
    return new DefaultMongoTemplate(mongo(), mongoDB);
}

@Bean
public MongoClient mongo() {
    MongoFactory mongoFactory = new MongoFactory();
    mongoFactory.setMongoAddresses(Collections.singletonList(new ServerAddress(mongoHost, mongoPort)));
    return mongoFactory.createMongo();
}

Axon 使用该索引来保证聚合上没有并发操作。毕竟Aggregate是一个一致性边界,它上面的所有状态变化都应该是原子的,高度一致的。

将索引更改为 non-unique 是个坏主意。它只允许插入与事件存储中已有的其他事件冲突的事件。

鉴于问题似乎在序列 #0,可能是您不小心将 @CommandHandler 方法建模为构造函数。 Axon 通过创建一个新实例来特殊对待这些命令处理程序,而不是尝试加载现有实例。在您的情况下,聚合已经存在,因为已经存储了一些事件。