引言:聊聊开发中那些让人头秃的查询逻辑
各位好,我是零点博客的博主。最近在维护老项目的时候,发现很多早期的代码在处理多条件搜索时,依然大量依赖直接拼接字符串,也就是所谓的“字符串注入”。这种方法不仅效率低,简直是SQL注入的重灾区。今天咱们就用 C# 和 PHP(EMLOG环境)两种后端视角,手把手教大家如何优雅、安全地编写SQL语句,并搭建一个通用的动态查询框架。
一、 为什么直接拼接字符串是“坑”
很多新手写SQL语句时,习惯把变量直接塞进字符串里。比如:
// PHP/EMLOG 这种写法非常危险!
$sql = "SELECT * FROM " . DB_PREFIX . "blog WHERE title LIKE '%$keyword%'";
看似没问题,但如果用户输入了 `` 作为搜索词,这就会直接暴露在 MySQL 的执行结果中,甚至被恶意利用。
二、 核心大招:预处理语句
无论是写 C# 的 SqlCommand 还是 PHP 的 PDO,预处理语句都是第一道防线。它将SQL语句的“骨架”与“血肉”分离,数据库只负责解析骨架,执行时才注入参数,从底层切断注入风险。
三、 实战演练:多条件动态查询构建
在实际开发中,搜索往往不是单一的。我们需要根据前端传来的参数(标题、分类、时间、作者)来动态生成SQL语句。这里有两种经典的实现思路。
方案A:C# 基础语法拼接(适合理解逻辑)
C# 中我们通常构建 StringBuilder,拼接字符串。注意看这里是如何通过变量控制是否添加条件,以及使用参数化查询的。
public List<Article> SearchArticles(string keyword, int? categoryId, DateTime? startDate)
{
var list = new List<Article>();
var sql = new StringBuilder("SELECT * FROM Article WHERE 1=1");
// 1. 拼接标题搜索条件
if (!string.IsNullOrEmpty(keyword))
{
sql.Append(" AND Title LIKE @Title");
parameters.Add(new SqlParameter("@Title", "%" + keyword + "%"));
}
// 2. 拼接分类条件
if (categoryId.HasValue)
{
sql.Append(" AND CategoryId = @CategoryId");
parameters.Add(new SqlParameter("@CategoryId", categoryId.Value));
}
// 3. 拼接日期范围
if (startDate.HasValue)
{
sql.Append(" AND CreateTime >= @StartDate");
parameters.Add(new SqlParameter("@StartDate", startDate.Value));
}
// 4. 排序
sql.Append(" ORDER BY CreateTime DESC");
// 执行查询
using (var cmd = new SqlCommand(sql.ToString(), conn))
{
// 填充参数...
// ... 执行读取逻辑
}
}
方案B:EMLOG + PHP 原生预处理(更轻量级)
在 EMLOG 这种轻量级 PHP 程序中,为了减少依赖库,我们有时需要原生处理。下面是一个模拟的 `where` 条件拼接辅助函数:
function buildWhereSql(array $params)
{
$where = [];
$bindValues = [];
// 模糊查询 title
if (!empty($params['keyword'])) {
$where[] = "title LIKE :title";
$bindValues[':title'] = '%' . $params['keyword'] . '%';
}
// 精确查询 cid (分类)
if (!empty($params['cid'])) {
$where[] = "cid = :cid";
$bindValues[':cid'] = intval($params['cid']);
}
// 精确查询 status (状态)
if (isset($params['status'])) {
$where[] = "status = :status";
$bindValues[':status'] = $params['status'];
}
// 将数组转换为 'WHERE a=1 AND b=2'
$sql = "SELECT * FROM " . DB_PREFIX . "blog ";
if (!empty($where)) {
$sql .= "WHERE " . implode(' AND ', $where);
}
$sql .= " ORDER BY date DESC LIMIT 10";
return ['sql' => $sql, 'bind' => $bindValues];
}
四、 底层避坑指南:MySQL 性能与索引
写好SQL语句只是第一步,如何让查询飞起来才是关键。
- 少用 SELECT *: 除非必要,尽量指定字段名。这能减少网络传输和内存消耗。
- 索引是王道: 如果你在 `WHERE` 子句里加了 `cid` 或者 `date`,务必确保这两个字段上有索引。否则,哪怕加了预处理,数据库引擎也要进行全表扫描,速度会慢得让你想砸键盘。
- LIKE 陷阱: 在使用 `LIKE '%keyword%'` 进行模糊查询时,如果字段没有索引,索引会直接失效,导致性能崩盘。
五、 总结
这次复盘其实就在做一件事:规范。无论你是用 C# 写复杂的接口,还是用 PHP 开发 EMLOG 插件,保持SQL语句的结构清晰、参数化使用习惯,是减少 Bug 和提高安全性的唯一捷径。希望这篇干货能帮大家少走弯路,代码少跑两遍。



评论一下吧
取消回复