跳到主要内容

12 - 最佳实践

12.1 使用建议

场景选择

场景推荐方式说明
简单 CRUDWrapper类型安全,推荐
动态表名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();
}