当前位置: 首页 > news >正文

SpringBoot学习日记 Day5:解锁企业级开发核心技能

一、前言:从玩具项目到生产系统

经过前四天的学习,我们已经能够开发基础功能了。但要让应用真正具备生产价值,还需要掌握数据库高级操作、事务控制、缓存优化等企业级开发技能。今天就来攻克这些关键知识点!

二、JPA进阶:让数据库操作更高效

1. 复杂查询的三种实现方式

方式一:方法名派生查询

public interface UserRepository extends JpaRepository<User, Long> {// 根据姓名模糊查询+年龄范围List<User> findByUsernameContainingAndAgeBetween(String name, Integer minAge, Integer maxAge);// 统计大于某年龄的用户数Long countByAgeGreaterThan(Integer age);
}

方式二:@Query注解(JPQL)

@Query("SELECT u FROM User u WHERE u.dept.id = :deptId AND u.status = :status")
List<User> findUsersByDeptAndStatus(@Param("deptId") Long deptId, @Param("status") Integer status);

方式三:原生SQL查询

@Query(value = "SELECT * FROM users WHERE reg_time > :date", nativeQuery = true)
List<User> findRecentUsers(@Param("date") Date date);

2. 分页查询最佳实践

@GetMapping("/users")
public PageResult<User> getUsers(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer size,@RequestParam(required = false) String name) {Pageable pageable = PageRequest.of(page - 1, size, Sort.by("createTime").descending());Page<User> userPage;if (StringUtils.isEmpty(name)) {userPage = userRepository.findAll(pageable);} else {userPage = userRepository.findByUsernameContaining(name, pageable);}return PageResult.success(userPage);
}

3. 关联关系实战(用户-部门示例)

实体类配置:

@Entity
@Data
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;@ManyToOne@JoinColumn(name = "dept_id")private Department department;
}@Entity
@Data
public class Department {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;@OneToMany(mappedBy = "department")private List<User> users;
}

查询优化建议:

1. 使用@EntityGraph解决N+1查询问题:

@EntityGraph(attributePaths = {"department"})
List<User> findAllWithDepartment();

2. 延迟加载时注意事务范围:

// 在Service层方法上添加事务注解
@Transactional(readOnly = true)
public User getUserDetail(Long id) {User user = userRepository.findById(id).orElseThrow();// 此时可以安全访问延迟加载的关联对象System.out.println(user.getDepartment().getName());return user;
}

三、事务管理:数据一致性的守护者

1. 声明式事务基础

@Service
@RequiredArgsConstructor
public class OrderService {private final OrderRepository orderRepository;private final UserRepository userRepository;@Transactionalpublic void createOrder(OrderDTO dto) {// 扣减用户余额User user = userRepository.findById(dto.getUserId()).orElseThrow(() -> new BusinessException("用户不存在"));user.setBalance(user.getBalance() - dto.getAmount());userRepository.save(user);// 创建订单Order order = new Order();// 设置订单属性...orderRepository.save(order);// 如果这里抛出异常,上面所有操作都会回滚}
}

2. 事务传播行为实验

传播行为说明适用场景
REQUIRED(默认)当前有事务则加入,没有则新建大多数业务方法
REQUIRES_NEW总是新建事务,挂起当前事务日志记录等独立操作
NESTED在当前事务嵌套子事务部分需要独立回滚的子流程

测试用例:

@Transactional
public void parentMethod() {// 操作1...childMethod();  // 测试不同传播行为// 操作2...
}@Transactional(propagation = Propagation.REQUIRES_NEW)
public void childMethod() {// 子方法操作...
}

四、Redis缓存:性能加速器

1. 集成Redis三步走

第一步:添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

第二步:配置连接

spring:redis:host: localhostport: 6379password: database: 0

第三步:启用缓存

@SpringBootApplication
@EnableCaching
public class MyApp {public static void main(String[] args) {SpringApplication.run(MyApp.class, args);}
}

2. 缓存注解实战

@Service
public class UserService {// 缓存查询结果@Cacheable(value = "user", key = "#id")public User getUserById(Long id) {return userRepository.findById(id).orElseThrow();}// 更新时清除缓存@CacheEvict(value = "user", key = "#user.id")public User updateUser(User user) {return userRepository.save(user);}// 条件缓存@Cacheable(value = "user", key = "#name", unless = "#result == null")public User getUserByName(String name) {return userRepository.findByUsername(name);}
}

五、文件操作:用户头像上传实战

1. 配置文件上传

spring:servlet:multipart:max-file-size: 2MBmax-request-size: 10MB

2. 实现上传接口

@PostMapping("/avatar/upload")
public Result<String> uploadAvatar(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {throw new BusinessException("请选择文件");}// 生成唯一文件名String fileName = UUID.randomUUID() + "." + FileUtil.getExtension(file.getOriginalFilename());// 保存文件Path path = Paths.get("uploads/avatars", fileName);try {Files.createDirectories(path.getParent());file.transferTo(path);} catch (IOException e) {throw new BusinessException("文件上传失败");}return Result.success("/avatars/" + fileName);
}

3. 文件下载实现

@GetMapping("/avatar/download/{filename:.+}")
public void downloadAvatar(@PathVariable String filename, HttpServletResponse response) throws IOException {Path path = Paths.get("uploads/avatars", filename);if (!Files.exists(path)) {response.sendError(404, "文件不存在");return;}response.setContentType("image/jpeg");Files.copy(path, response.getOutputStream());
}

六、今日成果:用户管理系统升级版

1. 数据库层:

   - 实现多表关联查询

   - 支持分页排序

   - 完善事务管理

2. 缓存层:

   - 高频查询结果缓存

   - 自动更新缓存策略

3. 文件操作:

   - 头像上传下载功能

   - 文件大小限制处理

4. API增强:

// 分页查询示例
GET /users?page=1&size=10&name=张&sort=age,desc// 头像上传
POST /avatar/upload// 带缓存的用户查询
GET /users/{id}

七、避坑指南

1. N+1查询问题:

   - 使用@EntityGraph或JOIN FETCH优化

   - 测试时开启SQL日志观察查询次数

2. 事务失效场景:

   - 方法必须是public

   - 自调用问题(AOP失效)

   - 异常类型默认只回滚RuntimeException

3. 缓存一致性:

   - 更新数据库后及时清除缓存

   - 考虑使用@CachePut更新缓存

4. 文件存储安全:

   - 校验文件类型(不要仅靠扩展名)

   - 限制上传目录权限

   - 考虑使用云存储服务

八、明日计划

1. 学习SpringBoot定时任务

2. 集成邮件发送功能

3. 实现系统监控端点

4. 探索AOP统一日志处理

思考题:在电商系统中,下单操作需要扣减库存、生成订单、扣减优惠券等多个步骤,该如何设计事务边界?欢迎评论区分享你的设计方案!

如果觉得这篇日记有帮助,请点赞收藏支持~完整代码示例可通过私信获取。在实际开发中遇到问题也欢迎留言讨论!

http://www.dtcms.com/a/320399.html

相关文章:

  • PCIe Base Specification解析(九)
  • 多线程的使用
  • 2025 最新 ECharts 下载、安装与配置教程
  • Linux 中断系统全览解析:从硬件到软件的全路线理解
  • Oracle 19C In-Memory 列存储技术测试
  • Qwen系列模型
  • [链表]两两交换链表中的节点
  • 【感知机】感知机(perceptron)学习算法的对偶形式
  • aurora rx没有ready信号
  • 哈希表——指针数组与单向链表的结合
  • linux顽固进程查看并清理
  • Java包装类详解与应用指南
  • SupChains技术团队:需求预测中减少使用分层次预测(五)
  • 目标检测数据集 - 眼睛瞳孔检测数据集下载「包含COCO、YOLO两种格式」
  • 菜鸟笔记007 [...c(e), ...d(i)]数组的新用法
  • (数据结构)顺序表实现-增删查改
  • java中override和overload的区别
  • 敏捷总结-上
  • 如果获取Docker镜像
  • Flink与Kafka核心源码详解-目录
  • 中国北极圈战略部署
  • 有密钥保护的物流跟踪、图书馆管理ISO15693标签ICODE SLIX2读写C#源码
  • 跨学科视域下的深层语义分析与人类底层逻辑一致性探索
  • 计数组合学7.15(Schur 函数的经典定义 )
  • 多模态融合(Multimodal Fusion)
  • 神策埋点是什么
  • C语言:单链表学习
  • 城市道路场景下漏检率↓76%:陌讯多模态融合算法在井盖缺失识别中的实践
  • Nestjs框架: 管道机制(Pipe)从校验到转换的全流程解析
  • ROS Launch 文件中的替换参数详解