本文目录导读:

在Java中实现唯一性校验通常需要结合数据库和业务逻辑来处理,以下是几种常见的实现方案:
数据库层面 - 唯一索引
创建唯一索引
-- 单字段唯一索引 CREATE UNIQUE INDEX idx_user_email ON users(email); -- 复合唯一索引 CREATE UNIQUE INDEX idx_user_email_phone ON users(email, phone);
MyBatis-Plus 注解方式
@Entity
@Table(name = "users", uniqueConstraints = {
@UniqueConstraint(columnNames = {"email"}),
@UniqueConstraint(columnNames = {"phone"})
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String email;
private String phone;
}
业务逻辑层校验
Spring Boot + JPA 实现
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
// 先查询是否存在
if (userRepository.existsByEmail(user.getEmail())) {
throw new BusinessException("邮箱已存在");
}
if (userRepository.existsByPhone(user.getPhone())) {
throw new BusinessException("手机号已存在");
}
return userRepository.save(user);
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);
boolean existsByPhone(String phone);
Optional<User> findByEmail(String email);
}
MyBatis 实现
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public int createUser(User user) {
// 业务层校验
User existingUser = userMapper.findByEmail(user.getEmail());
if (existingUser != null) {
throw new BusinessException("邮箱已存在");
}
return userMapper.insert(user);
}
}
@Mapper
public interface UserMapper {
User findByEmail(@Param("email") String email);
int insert(User user);
}
使用Spring Validation注解
自定义验证注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueEmailValidator.class)
public @interface UniqueEmail {
String message() default "邮箱已被注册";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
@Autowired
private UserRepository userRepository;
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
return email != null && !userRepository.existsByEmail(email);
}
}
使用在控制器中
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
// 业务逻辑
}
}
public class User {
@NotNull
@UniqueEmail
private String email;
@NotNull
@Size(min = 11, max = 11)
@Pattern(regexp = "^1[3-9]\\d{9}$")
private String phone;
}
处理并发情况 - 乐观锁
使用版本号
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
@Version
private Integer version; // 乐观锁版本号
}
@Service
public class UserService {
public User createUserWithLock(User user) {
try {
return userRepository.save(user);
} catch (OptimisticLockException e) {
throw new BusinessException("数据已被修改,请重试");
}
}
}
使用分布式锁
@Service
public class UserService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public User createUserWithDistributedLock(User user) {
String lockKey = "user:email:" + user.getEmail();
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS);
if (!Boolean.TRUE.equals(locked)) {
throw new BusinessException("邮箱已被注册");
}
try {
// 双重检查
if (userRepository.existsByEmail(user.getEmail())) {
throw new BusinessException("邮箱已存在");
}
return userRepository.save(user);
} finally {
redisTemplate.delete(lockKey);
}
}
}
完整示例 - 批量校验
@Slf4j
@Service
public class BatchValidationService {
@Autowired
private UserRepository userRepository;
/**
* 批量导入用户时进行唯一性校验
*/
public BatchImportResult batchImportUsers(List<User> users) {
BatchImportResult result = new BatchImportResult();
List<String> emails = users.stream()
.map(User::getEmail)
.collect(Collectors.toList());
// 批量查询已存在的数据
List<User> existingUsers = userRepository.findByEmailIn(emails);
Set<String> existingEmails = existingUsers.stream()
.map(User::getEmail)
.collect(Collectors.toSet());
List<User> validUsers = new ArrayList<>();
List<String> duplicateEmails = new ArrayList<>();
for (User user : users) {
if (existingEmails.contains(user.getEmail())) {
duplicateEmails.add(user.getEmail());
log.warn("邮箱 {} 已存在", user.getEmail());
} else {
validUsers.add(user);
}
}
// 批量保存
if (!validUsers.isEmpty()) {
userRepository.saveAll(validUsers);
}
result.setSuccessCount(validUsers.size());
result.setDuplicateCount(duplicateEmails.size());
result.setDuplicateEmails(duplicateEmails);
return result;
}
}
@Data
public class BatchImportResult {
private int successCount;
private int duplicateCount;
private List<String> duplicateEmails;
}
最佳实践建议
- 数据库唯一索引是基础保障:防止并发情况下的数据重复
- 业务层校验提供友好提示:提前发现重复,避免数据库异常
- 结合缓存提高性能:使用Redis等缓存热点数据的唯一性校验
- 处理并发竞争:使用数据库锁、分布式锁或版本号机制
- 批量操作优化:减少数据库查询次数,批量校验和保存
- 异步校验:对于非关键数据,可使用消息队列异步处理
选择合适的方案要根据具体业务场景、并发量、性能要求等因素综合考虑。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播