12 - 最佳实践
12.1 使用建议
场景选择
| 场景 | 推荐方式 | 说明 |
|---|---|---|
| 简单 CRUD | Wrapper | 类型安全,推荐 |
| 动态表名 | Maker | 灵活 |
| 复杂查询 | 原生 SQL / 预设 SQL | 可读性好 |
| 报表统计 | 预设 SQL | 便于维护 |
| 批量操作 | 批量 API | 性能好 |
代码组织
推荐分层:Controller + Service
适用场景:需要事务控制、业务逻辑复杂、需要复用的场景
// Service 层(处理业务逻辑和事务)
@Service
public class UserService {
@Transactional
public void createUserWithLog(User user) {
DB.Pojo.insert(user); // 自动回填主键到 user 对象
Long id = user.getId();
DB.Pojo.insert(new UserLog(id, "created"));
}
public List<User> findActiveUsers() {
return DB.Pojo.select(User.class)
.eq(User::getStatus, 1)
.queryBeanList();
}
}
// Controller 层(处理请求和响应)
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/users")
public void create(@RequestBody User user) {
userService.createUserWithLog(user);
}
@GetMapping("/users/active")
public List<User> listActive() {
return userService.findActiveUsers();
}
}
简化场景:Controller 直接调用
适用场景:简单查询、无事务需求、无复用性需求的场景
@RestController
public class UserController {
@GetMapping("/users")
public List<User> list(@RequestParam(required = false) Integer status) {
return DB.Pojo.select(User.class)
.eq(status != null, User::getStatus, status)
.queryBeanList();
}
@GetMapping("/users/{id}")
public User getById(@PathVariable Long id) {
return DB.Pojo.select(User.class)
.eq(User::getId, id)
.queryBean();
}
}
条件构建
// ✅ 推荐:条件判断前置
DB.Pojo.select(User.class)
.eq(status != null, User::getStatus, status)
.like(StringUtil.isNotBlank(name), User::getName, name)
.queryBeanList();
// ✅ 推荐:使用 Stream API
List<User> users = DB.Pojo.select(User.class).queryBeanList();
List<User> filteredUsers = users.stream()
.filter(user -> status != null && user.getStatus().equals(status))
.filter(user -> StringUtil.isNotBlank(name) && user.getName().contains(name))
.collect(Collectors.toList());
if (StringUtil.isNotBlank(name)) {
query.like(User::getName, name);
}
// ...太多 if-else
12.2 性能优化
查询优化
只查需要的字段
// ❌ 查询全部字段
DB.Pojo.select(User.class).queryBeanList();
// ✅ 只查需要的字段
DB.Pojo.select(User.class)
.select(User::getId, User::getName)
.queryBeanList();
分页查询
// 查询全部再截取
List<User> all = DB.Pojo.select(User.class).queryBeanList();
List<User> page = all.subList(0, 10);
// 数据库分页
Page<User> page = DB.Pojo.select(User.class)
.page(Page.build(1, 10))
.queryBeanPage();
避免 N+1 问题
// N+1 问题
List<Order> orders = DB.Pojo.select(Order.class).queryBeanList();
for (Order order : orders) {
User user = DB.Pojo.select(User.class)
.eq(User::getId, order.getUserId())
.queryBean(); // 每次循环都查询
}
// 批量查询
List<Order> orders = DB.Pojo.select(Order.class).queryBeanList();
List<Long> userIds = orders.stream()
.map(Order::getUserId)
.distinct()
.collect(Collectors.toList());
Map<Long, User> userMap = DB.Pojo.select(User.class)
.in(User::getId, userIds)
.queryBeanList()
.stream()
.collect(Collectors.toMap(User::getId, u -> u));
写入优化
批量插入
// ❌ 循环单条插入
for (User user : users) {
DB.Pojo.insert(user);
}
// ✅ 批量插入
DB.Batch.insert(users);
12.3 安全规范
SQL 注入防护
使用参数化查询
// 安全:参数化查询
DB.Pojo.select(User.class)
.eq(User::getName, userInput)
.queryBeanList();
// 安全:使用 #{} 占位符
DB.Sql.select("user.find")
.addPara("name", userInput)
.queryList();
// 安全:使用 ? 占位符
DB.Jdbc.select("SELECT * FROM user WHERE name = ?", userInput)
.queryList();
// 危险:字符串拼接
String sql = "SELECT * FROM user WHERE name = '" + userInput + "'";
动态排序安全
// ❌ 危险:直接使用用户输入
String sort = request.getParameter("sort");
query.addPara("sortField", sort);
// ✅ 安全:白名单校验
Set<String> ALLOWED_SORTS = Set.of("id", "name", "create_time");
String sort = request.getParameter("sort");
if (!ALLOWED_SORTS.contains(sort)) {
sort = "create_time"; // 默认值
}
query.addPara("sortField", sort);
敏感数据处理
// 日志脱敏(配置)
dlz:
db:
// 需要脱敏的字段
sensitive-fields:
- password
- phone
权限控制
// 数据权限过滤
public List<Order> findMyOrders() {
Long currentUserId = SecurityContext.getCurrentUserId();
return DB.Pojo.select(Order.class)
.eq(Order::getUserId, currentUserId) // 只能看自己的
.queryBeanList();
}