如何使用Java 8 Stream实现用户列表入库并校验重复抛出异常
实现方案
原有代码问题分析
- 语法错误:
userList.stream(多了多余的左括号,正确写法为userList.stream() - filter逻辑误用:filter仅用于筛选元素,
Optional.isPresent()是无参方法,不能直接传入异常对象实现存在即抛异常的逻辑 - 流程逻辑缺失:原代码即使修复语法问题,也仅能筛选出已存在的用户,不会触发异常终止流程,且最终保存的仍是未校验的原始用户列表
基础实现(单条查询校验)
如果你不需要考虑大批量用户的性能问题,可以直接按单条遍历校验的逻辑实现,代码如下:
public List<User> addUsers(@RequestBody List<User> userList) { userList.stream() // 筛选出数据库中已存在的用户 .filter(user -> userRepository.findByEmail(user.getEmail()).isPresent()) // 取第一个匹配到的已存在用户 .findFirst() // 如果存在已存在的用户则直接抛出异常 .ifPresent(existUser -> { throw new ResourceAlreadyExistsException("User with", String.format(" email %s already exists", existUser.getEmail())); }); // 所有用户校验通过,批量入库 return userRepository.saveAll(userList); }
优化实现(批量查询校验,性能更高)
如果传入的用户列表量级较大,单条查询数据库会产生大量IO请求,建议改用批量查询的方式优化:
- 首先在你的
UserRepository接口中新增批量查询邮箱的方法:
// 返回所有已存在的邮箱列表 List<String> findEmailByEmailIn(List<String> emailList);
- 调整接口逻辑:
public List<User> addUsers(@RequestBody List<User> userList) { // 提取所有待新增用户的邮箱 List<String> emailList = userList.stream() .map(User::getEmail) .collect(Collectors.toList()); // 批量查询数据库中已存在的邮箱 List<String> existEmailList = userRepository.findEmailByEmailIn(emailList); // 存在重复邮箱直接抛出异常,可返回所有重复的邮箱提示 if (!existEmailList.isEmpty()) { throw new ResourceAlreadyExistsException("User with", String.format(" emails %s already exist", String.join(",", existEmailList))); } return userRepository.saveAll(userList); }
注意事项
- 建议给该方法加上
@Transactional注解保证操作原子性,避免并发场景下校验完成后、入库前有其他请求插入相同邮箱的用户 - 数据库层面需要给
email字段添加唯一索引,作为最终兜底校验,避免极端并发场景下出现重复数据
内容的提问来源于stack exchange,提问作者user9347049
相关产品推荐
相关产品推荐

