MySQLi需手动类型转换后字符串拼接,PDO须用bindValue指定PDO::PARAM_INT绑定LIMIT参数;LIMIT offset,row_count中offset从0开始,分页应为($page-1)*$limit;COUNT(*)需单独查询,参数必须强转整型并设上限。

PHP中MySQLi和PDO的LIMIT写法差异
PHP本身没有LIMIT语法,它只是把LIMIT作为SQL语句的一部分传给数据库执行。关键区别在于:MySQLi用字符串拼接或预处理绑定,PDO支持占位符但LIMIT参数不能直接用问号占位(会报错或被当字符串处理)。
- MySQLi原生写法:
$sql = "SELECT * FROM users LIMIT " . (int)$offset . ", " . (int)$limit;—— 必须手动类型转换,否则SQL注入风险极高 - PDO安全写法:
$sql = "SELECT * FROM users LIMIT ?, ?"; $stmt = $pdo->prepare($sql); $stmt->bindValue(1, $offset, PDO::PARAM_INT); $stmt->bindValue(2, $limit, PDO::PARAM_INT); - 错误示范:
$stmt->execute([$offset, $limit]);在部分PDO驱动下会导致LIMIT参数被转义为字符串,查不出数据
MySQL的LIMIT offset, row_count到底怎么算起始位置
LIMIT 5, 10 表示跳过前5条,取接下来的10条,即第6–15条记录。这个“5”是偏移量(offset),不是页码。做分页时容易误写成LIMIT ($page * $limit), $limit,结果第1页就跳过了$limit条。
- 正确分页计算:
$offset = ($page - 1) * $limit;,然后LIMIT $offset, $limit - 注意:MySQL 8.0+支持
LIMIT row_count OFFSET offset写法(如LIMIT 10 OFFSET 5),语义更清晰,但旧版本不兼容 - 如果
$offset为负数或非整数,MySQL直接报错ERROR 1064,PHP里需提前校验
使用LIMIT后COUNT(*)总数怎么获取
加了LIMIT的查询查不到总条数,必须额外执行一次COUNT(*)。但别用SELECT COUNT(*) FROM table WHERE ...再套一遍条件——条件复杂时易出错且性能差。
- 推荐方式:用SQL_CALC_FOUND_ROWS(已废弃,仅限MySQL 5.7及以前)或改用子查询+FOUND_ROWS(),但更稳妥的是单独发一条
COUNT语句 - 实际项目中常封装成两个方法:
getItems($limit, $offset)和getTotalCount(),后者复用相同WHERE逻辑 - 注意:ORM如Laravel的
paginate()自动处理了总数查询,但底层仍是两次查询,大数据量时要考虑缓存count结果
PHP中LIMIT参数没过滤导致的致命问题
用户可控的$limit或$offset若未强转为整型,可能引发SQL注入或语法错误。比如?limit=10; DROP TABLE users--在拼接场景下极危险。
立即学习“PHP免费学习笔记(深入)”;
- 必须用
(int)或filter_var($val, FILTER_VALIDATE_INT)强制转换,不能只用intval()(它对"10abc"也返回10) - 设置合理上限:如
$limit = min(100, (int)$limit);,防止恶意拉取海量数据拖垮数据库 - 某些框架(如CodeIgniter)的
$this->db->limit()会自动转义,但原生PDO/MySQLi不会——这点常被忽略
真正麻烦的不是写LIMIT,而是确保每个传入的数字都经过类型校验、范围限制和上下文隔离。少一个(int),线上就可能多一次慢查询或一次注入。











