我面临的问题是间歇性的,并且只在生产环境中重载时发生。MongoDB在replica set模式下设置了一个仲裁器
我有一个UserDetail类
@Builder
@Data
@Document(collection = "user_details")
public class UserDetail {
private List<String> params;
@Id
private ObjectId id;
@Indexed(name = "idx_us_de_on_user_id", unique = true)
private UUID userId;
}
在服务层保存之前,我首先通过以下代码检查它是否存在:
UserDetail userDetail =
Optional.ofNullable(
mongoTemplateReadPreferencePrimary
.query(UserDetail.class)
.matching(
query(where("userId").is(userId))
)
.firstValue()
)
.orElse(
UserDetail.builder()
.userId(userId)
.params(new ArrayList<>())
.build()
);
// perform business logic
// then try to save userDetail
userDetailRepository.save(userDetail);
存储库层如下:
@Repository
public interface UserDetailRepository extends MongoRepository<UserDetail, ObjectId> {
Optional<UserDetail> findByUserId(UUID userId);
}
但是在高负载的生产环境中有时会出现错误
Write error: WriteError{code=11000, message='E11000 duplicate key error collection: database_name.user_details index: userId_1 dup key: { userId: UUID("b5261508-fdc8-4f30-b358-5d37374cf9f9") }', details={}}
我试过使用readConcern作为primary,但是没有帮助。
通常有一个竞争条件。两个并发的更新同一个UserDetail
的请求会发现实体不存在,并尝试进行插入,其中一个会抛出一个重复键错误
选项:
- 实现
Persistable
与isNew()
假所以保存总是一个向上设置 - 实现业务逻辑,使您总是做两次尝试。第二次尝试只有当你得到一个重复的键异常