Spring Boot中如何优雅为新增Setting对象设置正确优先级?
优化方案:Spring Boot + MongoDB 自动设置优先级
这里有几种更优雅且实用的优化方案,兼顾代码简洁性和并发安全性:
一、先解决核心隐患:并发场景下的优先级重复问题
你的现有实现存在并发风险:当多个请求同时新增同type的Setting时,可能同时查询到相同的最大优先级,导致最终存入重复的优先级。推荐用MongoDB的原子操作来解决这个问题,同时简化代码。
实现方式:使用findAndModify原子操作
// 1. 构建查询条件:匹配目标type Query query = Query.query(Criteria.where("type").is(setting.getType())); // 2. 构建更新规则:自动递增优先级,首次插入时设置基础字段 Update update = new Update() .inc("priority", 1) // 已有同type文档时,优先级+1 .setOnInsert("name", setting.getName()) // 仅插入新文档时设置name .setOnInsert("type", setting.getType()); // 仅插入新文档时设置type // 3. 执行原子操作:查询并更新,无匹配则插入新文档 Setting existingMax = mongoTemplate.findAndModify( query, update, new FindAndModifyOptions() .returnNew(false) // 返回更新前的文档(用于判断是否是首次插入) .upsert(true), // 无匹配则插入新文档 Setting.class ); // 4. 给传入的Setting对象设置最终优先级 setting.setPriority(existingMax == null ? 1 : existingMax.getPriority() + 1); // 注意:如果不需要保留传入对象的引用,也可以直接使用findAndModify返回的新文档(把returnNew设为true)
这种方式全程是原子操作,彻底避免了并发下的优先级重复问题,代码也比原实现简洁。
二、仅优化代码优雅性(不考虑并发)
如果你的场景并发量极低,只想让代码更简洁,可通过Optional简化繁琐的null判断:
Aggregation priorityAggregation = Aggregation.newAggregation( Aggregation.match(Criteria.where("type").is(setting.getType())), Aggregation.group().max("priority").as("maxPriority"), Aggregation.project("maxPriority").andExclude("_id") ); // 用Optional链式处理null情况 Integer maxPriority = Optional.ofNullable( mongoTemplate.aggregate(priorityAggregation, "setting", HashMap.class).getUniqueMappedResult() ) .map(result -> (Integer) result.get("maxPriority")) .orElse(null); setting.setPriority(maxPriority != null ? maxPriority + 1 : 1); mongoTemplate.save(setting);
三、按Spring Data规范封装逻辑
将优先级查询逻辑封装到Repository中,让业务代码更清晰,符合单一职责原则:
1. 定义自定义Repository方法
public interface SettingRepository extends MongoRepository<Setting, ObjectId> { @Aggregation(pipeline = { "{ '$match': { 'type': ?0 } }", "{ '$group': { '_id': null, 'maxPriority': { '$max': '$priority' } } }", "{ '$project': { '_id': 0, 'maxPriority': 1 } }" }) Optional<Map<String, Integer>> findMaxPriorityByType(String type); }
2. 业务层调用
@Autowired private SettingRepository settingRepository; public Setting createSetting(Setting setting) { Integer maxPriority = settingRepository.findMaxPriorityByType(setting.getType()) .map(result -> result.get("maxPriority")) .orElse(null); setting.setPriority(maxPriority != null ? maxPriority + 1 : 1); return settingRepository.save(setting); }
这种方式把数据访问逻辑从业务层抽离,代码结构更清晰,也便于后续维护。
内容的提问来源于stack exchange,提问作者TheStranger
相关产品推荐
相关产品推荐

