【问题标题】:Is there anyway to disable "Retryable writes" to false in Spring Boot 2.2.1无论如何在 Spring Boot 2.2.1 中将“可重试写入”禁用为 false
【发布时间】:2022-01-06 12:30:20
【问题描述】:

第一次

我正在尝试开发一个控制器来将DocumentDB 中的数据保存在AWS 中。

第一次保存,但第二次,我正在寻找保存在数据库中的这个寄存器,我得到了这个并更改了一些数据,然后保存,但是......

我收到此错误:

Caused by: com.mongodb.MongoCommandException: Command failed with error 301: 'Retryable writes are not supported' on server aws:27017. The full response is {"ok": 0.0, "code": 301, "errmsg": "Retryable writes are not supported", "operationTime": {"$timestamp": {"t": 1641469879, "i": 1}}}

这是我的java代码

@Service
public class SaveStateHandler extends Handler<SaveStateCommand> {

    @Autowired
    private MongoRepository repository;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public String handle(Command command) {

        SaveStateCommand cmd = (SaveStateCommand) command;

        State state = buildState(cmd);

        repository.save(state);

        return state.getId();
    }

    private State buildState(SaveStateCommand cmd) {

        State state = State
                .builder()
                .activityId(cmd.getActivityId())
                .agent(cmd.getAgent())
                .stateId(cmd.getStateId())
                .data(cmd.getData())
                .dataAlteracao(LocalDateTime.now())
                .build();

        State stateFound = findState(cmd);

        if (stateFound != null) {
            state.setId(stateFound.getId());
        }

        return state;
    }

    private State findState(SaveStateCommand request) {

        Query query = new Query();

        selectField(query);
        where(request, query);

        return mongoTemplate.findOne(query, State.class);
    }

    private void selectField(Query query) {
        query.fields().include("id");
    }

    private void where(SaveStateCommand request, Query query) {
        query.addCriteria(new Criteria().andOperator(
                Criteria.where("activityId").is(request.getActivityId()),
                Criteria.where("agent").is(request.getAgent())));
    }
}

AWS 中,他们建议使用retryWrites=false,但我不知道如何在Spring Boot 中使用。

我用Spring Boot 2.2.1

我尝试过这样做

    @Bean
    public MongoClientSettings mongoSettings() {
        return MongoClientSettings
                .builder()
                .retryWrites(Boolean.FALSE)
                .build();
    }

但没用。

=================================================================================

第二次

我使用 SSH 隧道连接到 AWS DocumentDb。

使用这些数据库配置启动我的应用程序

@Configuration
@EnableConfigurationProperties({MongoProperties.class})
public class MongoAutoConfiguration {

    private final MongoClientFactory factory;
    private final MongoClientOptions options;
    private MongoClient mongo;

    public MongoAutoConfiguration(MongoProperties properties, ObjectProvider<MongoClientOptions> options, Environment environment) {

        this.options = options.getIfAvailable();

        if (StringUtils.isEmpty(properties.getUsername()) || StringUtils.isEmpty(properties.getPassword())) {
            properties.setUsername(null);
            properties.setPassword(null);
        }

        properties.setUri(createUri(properties));

        this.factory = new MongoClientFactory(properties, environment);
    }

    private String createUri(MongoProperties properties) {

        String uri = "mongodb://";

        if (StringUtils.hasText(properties.getUsername()) && !StringUtils.isEmpty(properties.getPassword())) {
            uri = uri + properties.getUsername() + ":" + new String(properties.getPassword()) + "@";
        }

        return uri + properties.getHost() + ":" + properties.getPort() + "/" + properties.getDatabase() + "?retryWrites=false";
    }

    @PreDestroy
    public void close() {
        if (this.mongo != null) {
            this.mongo.close();
        }
    }

    @Bean
    public MongoClient mongo() {
        this.mongo = this.factory.createMongoClient(this.options);
        return this.mongo;
    }
}

并且在本地,它会正确保存数据。

但是,如果我将 API 更新放入 AWS ECS 并尝试保存,则会出现相同的错误。

=================================================================================

依赖关系

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-mongodb</artifactId>
            <version>4.1.4</version>
        </dependency>

【问题讨论】:

  • @MuratKara 但我做到了,但仍然遇到同样的错误。
  • @DiegoMacario,您在本地和 aws 中的数据库版本是什么?
  • 另外,你在 pom 中对 mongo db 的依赖是什么?
  • @AnandVarkeyPhilips 他们是一样的。 Version 4.0.0

标签: java spring spring-boot aws-documentdb


【解决方案1】:

当您构建连接字符串时,您可以包含用于禁用可重试写入的参数,方法是将其添加到您的连接 URI:

?replicaSet=rs0&readPreference=primaryPreferred&retryWrites=false&maxIdleTimeMS=30000

然后在创建数据库工厂和mongo模板的时候使用这个(本例使用的是Reactive数据库工厂,但是SimpleMongoClientDatabaseFactory的原理是一样的:

@Bean
fun reactiveMongoDatabaseFactory(
        @Value("\${spring.data.mongodb.uri}") uri: String,
        @Value("\${mongodb.database-name}") database: String
): ReactiveMongoDatabaseFactory {
    val parsedURI = URI(uri)
    return SimpleReactiveMongoDatabaseFactory(MongoClients.create(uri), database)
}

【讨论】:

  • 如果你看我的代码,你会发现我把参数放在了uri中。
  • 您确定数据库名称应该是 URI @DiegoMacario 的一部分吗?我们没有使用它,并且在 AWS 生成的 URI 中,它也不是连接字符串的一部分:mongodb://xxxx:yyy@clusterurl.eu-west-1.docdb.amazonaws.com:27017/?replicaSet=rs0&amp;readPreference=secondaryPreferred&amp;retryWrites=false
猜你喜欢
  • 2020-02-15
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 2016-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-08
相关资源
最近更新 更多