like() 默认前后加%导致性能差且易误判,须显式指定第三个参数控制通配符位置;多字段OR匹配需用group_start()/group_end()包裹;分页需启用query_string模式并配置permitted_uri_chars。

like() 方法默认行为容易导致匹配失败
直接调用 $this->db->like('field', $value) 会生成 WHERE field LIKE '%value%',也就是前后都加 %。这在搜索“包含某子串”时没问题,但如果你传入的是完整值(比如用户输入“张三”,而数据库里存的就是“张三”),它仍会查 '%张三%' —— 逻辑上没错,但性能差、索引失效,且容易被误认为“没查到”。更关键的是,当字段本身带空格或不可见字符时,% 包裹反而掩盖了真实不匹配原因。
指定通配符位置才能精准控制匹配逻辑
like() 第三个参数决定 % 插入位置,必须显式传,不能依赖默认值。常见组合:
-
$this->db->like('name', 'tom', 'after')→name LIKE 'tom%'(开头匹配) -
$this->db->like('name', 'tom', 'before')→name LIKE '%tom'(结尾匹配) -
$this->db->like('name', 'tom', 'both')→name LIKE '%tom%'(任意位置)
注意:'after' 和 'before' 不会自动 trim 输入值,如果 $value 带首尾空格,生成的 SQL 就是 'tom %' 或 '% tom',很可能查不到数据。务必先 trim($value)。
多字段 OR 匹配必须用 group_start()/group_end()
想实现“在 first_name 或 last_name 中任一字段以某字符串开头”,不能写:
$this->db->like('first_name', $prefix, 'after');
$this->db->or_like('last_name', $prefix, 'after');
这样生成的 SQL 是 WHERE first_name LIKE 'xxx%' OR last_name LIKE 'xxx%',但若前面还有其他 where() 条件(比如 status = 'active'),OR 会破坏 AND 优先级,变成 (status = 'active' AND first_name LIKE 'xxx%') OR last_name LIKE 'xxx%' —— 显然不是本意。
正确写法是:
$this->db->group_start();
$this->db->like('first_name', $prefix, 'after');
$this->db->or_like('last_name', $prefix, 'after');
$this->db->group_end();
这样才确保 OR 被括号包裹,和外部条件保持 AND 关系。
模糊搜索 + 分页时 query string 会丢失
用 GET 提交搜索关键词(如 ?q=tom)后分页链接默认不带这个参数,点第二页就回到无搜索状态。解决方法不是拼 URL,而是启用 Query String 模式:
$config['page_query_string'] = TRUE; $config['query_string_segment'] = 'per_page';
然后分页类会自动保留所有 GET 参数。但要注意:如果关键词含特殊字符(如 +、(、)),需提前在 config.php 的 permitted_uri_chars 中放开,否则 CI 会在路由层直接 400 拒绝请求。
真正麻烦的从来不是写对一个 like(),而是确认 $value 是否被前端 trim 过、是否被 XSS 过滤意外截断、是否在分页跳转时被丢弃、以及 MySQL 的 collation 是否区分大小写或忽略空格 —— 这些地方一漏,查不到数据时你根本看不出哪步出了问题。


















