一、Spring 事务管理
基本概念
- 事务是一组原子性的数据库操作,要么全部成功,要么全部失败回滚
- 遵循ACID原则:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
Spring 事务管理实现方式
1. 声明式事务(@Transactional)
java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void saveUser(User user) {
userRepository.save(user);
// 如果后续操作抛出异常,整个方法会回滚
}
}
2. 编程式事务
java
@Service
public class UserService {
@Autowired
private TransactionTemplate transactionTemplate;
public void saveUser(User user) {
transactionTemplate.execute(status -> {
try {
// 执行业务逻辑
userRepository.save(user);
return null;
} catch (Exception e) {
status.setRollbackOnly(); // 手动标记回滚
throw e;
}
});
}
}
二、数据验证
对于验证手段的选择,建议采用组合使用的方式,不同层次使用不同的验证机制:
1. Controller层:Bean Validation
什么是Bean Validation
Bean Validation 是 Java EE 规范中的一部分,基于 JSR-380 (Java Specification Request 380) 标准,提供了一套通过注解来验证 Java Bean 属性的框架。
工作原理
- 在 DTO 或实体类字段上添加验证注解
- 在 Controller 方法参数前使用 @Valid 注解
- 当请求到达时自动执行验证
- 验证失败时抛出 MethodArgumentNotValidException 异常
java
public class User {
@NotNull(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄不能小于18岁")
private Integer age;
// getters and setters
}
- 使用
@Valid和 DTO 上的约束注解(如@NotBlank、@Email等) - 处理基础的数据格式验证
- 优点:标准化、减少样板代码、易于维护
java
@PostMapping("/register")
public ResponseEntity<RegisterResponse> register(@RequestBody @Valid UserRegisterRequest request) {
// ...
}
2. Service层:业务逻辑验证
- 处理业务相关的验证,如:
- 用户名是否已存在 (
userRepository.existsByUsername()) - 邮箱是否已被注册 (
userRepository.existsByEmail()) - 密码匹配验证 (
passwordUtil.matches())
- 用户名是否已存在 (
3. 优势对比
| 验证方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Bean Validation | 基础数据格式验证 | 标准化、简洁、易读 | 无法处理复杂业务逻辑 |
| 手动验证 | 复杂业务规则 | 灵活性高、可控性强 | 代码量大、容易遗漏 |
4. 最佳实践
- Controller层使用 Bean Validation 进行初步验证
- Service层保留必要的业务逻辑验证
- 既保证了代码的规范性,又维持了业务逻辑的完整性
- 提供更好的安全性和用户体验
这样的组合方式能充分发挥两种验证手段的优势,是目前最推荐的做法。
三、验证码验证逻辑设计
验证码生成与存储
java
@Component
public class CaptchaService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 生成验证码
*/
public String generateCaptcha(String key) {
String captcha = generateRandomCode(6);
// 存储到Redis,设置5分钟过期
redisTemplate.opsForValue().set("captcha:" + key, captcha, 5, TimeUnit.MINUTES);
return captcha;
}
/**
* 验证验证码
*/
public boolean validateCaptcha(String key, String inputCaptcha) {
String storedCaptcha = redisTemplate.opsForValue().get("captcha:" + key);
if (storedCaptcha == null) {
return false; // 验证码已过期或不存在
}
boolean isValid = storedCaptcha.equalsIgnoreCase(inputCaptcha);
if (isValid) {
// 验证成功后删除验证码,防止重复使用
redisTemplate.delete("captcha:" + key);
}
return isValid;
}
private String generateRandomCode(int length) {
String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder code = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
code.append(chars.charAt(random.nextInt(chars.length())));
}
return code.toString();
}
}
验证码控制器
java
@RestController
@RequestMapping("/api/captcha")
public class CaptchaController {
@Autowired
private CaptchaService captchaService;
/**
* 获取验证码
*/
@GetMapping("/generate")
public ResponseEntity<Map<String, String>> generateCaptcha(
@RequestParam String mobile) {
String captcha = captchaService.generateCaptcha(mobile);
// 实际项目中这里应该发送短信
Map<String, String> response = new HashMap<>();
response.put("message", "验证码已发送");
return ResponseEntity.ok(response);
}
/**
* 验证验证码接口
*/
@PostMapping("/validate")
public ResponseEntity<Map<String, Object>> validateCaptcha(
@RequestParam String mobile,
@RequestParam String captcha) {
boolean isValid = captchaService.validateCaptcha(mobile, captcha);
Map<String, Object> response = new HashMap<>();
response.put("valid", isValid);
if (isValid) {
response.put("message", "验证成功");
} else {
response.put("message", "验证码错误或已过期");
return ResponseEntity.badRequest().body(response);
}
return ResponseEntity.ok(response);
}
}
结合业务逻辑使用验证码
java
@RestController
public class RegisterController {
@Autowired
private CaptchaService captchaService;
@Autowired
private UserService userService;
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody RegisterRequest request) {
// 1. 验证验证码
if (!captchaService.validateCaptcha(request.getMobile(), request.getCaptcha())) {
return ResponseEntity.badRequest()
.body(Map.of("error", "验证码错误或已过期"));
}
// 2. 执行注册逻辑(在事务中)
try {
userService.registerUser(request);
return ResponseEntity.ok(Map.of("message", "注册成功"));
} catch (Exception e) {
return ResponseEntity.badRequest()
.body(Map.of("error", "注册失败: " + e.getMessage()));
}
}
}
这种设计模式的优势:
- 事务管理:保证数据一致性,异常时自动回滚
- 数据验证:在多个层次进行验证,提高系统健壮性
- 验证码机制:防止恶意注册和攻击
- 异常处理:统一处理各种异常情况,提供友好的错误提示
四、异常回退
异常回退(Fallback)是微服务架构中的一种容错机制,主要用于处理服务调用失败的情况。
1. 定义
- 当主调用流程出现异常(如网络超时、服务不可用等)时,系统自动切换到预设的备用处理逻辑
- 确保系统在部分组件失效时仍能继续提供服务
2. 应用场景
- 网络连接超时或中断
- 微服务实例宕机或不可达
- 数据库连接失败
- 第三方API调用失败
3. 实现方式
通常通过以下注解实现:
@HystrixCommand(fallbackMethod = "methodName")@Retryable配合@Recover
4. 示例
java
@HystrixCommand(fallbackMethod = "getDefaultData")
public String getDataFromRemoteService() {
// 主要业务逻辑
}
public String getDefaultData() {
// 回退逻辑,返回默认值或缓存数据
return "default data";
}
5. 优势
- 提高系统可用性
- 防止故障扩散
- 改善用户体验
- 增强系统稳定性