苍穹外卖Day4
文章目录
- 一、数据库操作问题排查
- 1. 数据库未选择错误及解决
- 2. 表不存在错误及排查方案
- 二、动态获取用户ID实现
- 1. 问题背景
- 2. 解决方案:ThreadLocal技术
- ThreadLocal核心方法与原理
- 拦截器与Service协作流程
- 三、分页查询架构设计
- 1. 分页结果统一封装(PageResult)
- 2. 序列化的必要性
- 3. 统一响应格式(Result<PageResult>)
- 4. JSON转换原理
- 四、开发实践总结
- 1. 关键问题解决路径
- 2. 架构设计价值矩阵
一、数据库操作问题排查
1. 数据库未选择错误及解决
-- 错误信息:
ERROR 1046 (3D000): No database selected-- 解决方案:
-- 查看所有数据库
SHOW DATABASES;-- 选择目标数据库
USE sky_take_out;-- 验证数据库变更
SELECT DATABASE();
2. 表不存在错误及排查方案
-- 错误信息:
ERROR 1146 (42S02): Table 'sky_take_out.sky_take_out' doesn't exist-- 排查步骤:
-- 查看当前数据库中的所有表
SHOW TABLES;-- 结果示例:
+-------------------------+
| Tables_in_sky_take_out |
+-------------------------+
| employees |
| departments |
| positions |
+-------------------------+-- 正确执行删除操作(假设实际表名是employees)
DELETE FROM employees WHERE username = 'wangwu';
关键技巧:使用
DESCRIBE table_name
查看表结构,确认字段名正确性
二、动态获取用户ID实现
1. 问题背景
在新增员工时,创建人ID和修改人ID需要动态获取(而非固定值)
2. 解决方案:ThreadLocal技术
ThreadLocal核心方法与原理
public class BaseContext {// 必须使用static保证线程间数据隔离private static final ThreadLocal<Long> THREAD_LOCAL = new ThreadLocal<>();public static void setCurrentId(Long id) {THREAD_LOCAL.set(id);}public static Long getCurrentId() {return THREAD_LOCAL.get();}public static void removeCurrentId() {THREAD_LOCAL.remove(); // 防止内存泄漏}
}
底层原理:
- 每个Thread维护一个ThreadLocalMap
- Key为ThreadLocal实例,Value为存储的值
- 线程隔离,避免并发冲突
拦截器与Service协作流程
关键代码实现:
// JWT拦截器中
String token = request.getHeader("Authorization");
Long empId = JwtUtil.parseToken(token).getEmpId();
BaseContext.setCurrentId(empId);// EmployeeService中
public void saveEmployee(Employee employee) {Long currentId = BaseContext.getCurrentId();employee.setCreateUser(currentId);employee.setUpdateUser(currentId);employeeMapper.insert(employee);
}
三、分页查询架构设计
1. 分页结果统一封装(PageResult)
public class PageResult<T> implements Serializable {private List<T> records; // 当前页数据列表private long total; // 总记录数private int size; // 每页大小private int current; // 当前页码// 计算总页数(避免前端重复计算)public int getPages() {return (int) Math.ceil((double) total / size);}
}
2. 序列化的必要性
// 实现Serializable接口
private static final long serialVersionUID = 1L;
序列化应用场景:
- 网络传输:HTTP响应本质是字节流传输
- 缓存系统:Redis/Memcached存储对象
- 分布式系统:跨JVM通信
- RPC框架:Dubbo/gRPC调用
3. 统一响应格式(Result)
public class Result<T> implements Serializable {private int code; // 状态码(200=成功)private String msg; // 提示信息private T data; // 业务数据public static <T> Result<T> success(T data) {Result<T> result = new Result<>();result.setCode(200);result.setMsg("操作成功");result.setData(data);return result;}
}
前端响应示例:
{"code": 200,"msg": "查询成功","data": {"records": [{"id": 1, "name": "张三", "dept": "研发部"},{"id": 2, "name": "李四", "dept": "市场部"}],"total": 50,"size": 10,"current": 1,"pages": 5}
}
4. JSON转换原理
Spring Boot处理流程:
技术优势:
- 跨平台兼容:JSON是Web标准数据格式
- 数据压缩:比XML体积小30-70%
- 解析高效:JavaScript原生支持JSON解析
- 类型安全:强类型语言无缝对接
四、开发实践总结
1. 关键问题解决路径
2. 架构设计价值矩阵
设计决策 | 解决问题 | 实现价值 |
---|---|---|
ThreadLocal应用 | 线程间数据传递 | 安全隔离,避免并发冲突 |
PageResult封装 | 分页结构不一致 | 前端统一解析逻辑 |
Serializable实现 | 网络传输/缓存需求 | 支持分布式架构 |
Result | API响应格式标准化 | 错误处理统一规范 |
JSON自动转换 | 前后端数据格式差异 | 提升跨平台兼容性 |
分层架构优势:
- DAO层:聚焦SQL执行和数据获取
- Service层:处理业务逻辑和分页封装
- Controller层:管理HTTP交互和响应格式
- 前端层:专注数据渲染和用户交互
开发心得:通过合理的架构分层和标准化设计,显著提升系统的可维护性和扩展性
如果内容对您有帮助,请点赞👍、关注❤️、收藏⭐️。您的支持是我创作的动力!