查数据必须用db::query(),改数据必须用db::execute();query返回结果集仅适用于select等语句,execute返回影响行数用于insert/update/delete;参数须用占位符绑定,表名字段名需白名单校验;事务中禁用不支持回滚的语句。

刚接触ThinkPHP的新手常遇到一个问题:明明写了SQL语句,却查不到数据或改不进数据库,根本原因是没分清query和execute的用途——查数据必须用query,改数据必须用execute,混用会导致返回值错乱、逻辑误判甚至数据静默丢失。
查数据:用Db::query()获取结果数组
这一步操作起来很简单,直接把带SELECT的SQL丢进去就行。但注意:只有SELECT、SHOW、EXPLAIN这类返回结果集的语句才适用,其他一律报错或返回空。
Db::query('SELECT * FROM user WHERE status = ? AND id > ?', [1, 100]);
命名占位符写法更清晰:Db::query('SELECT id,name FROM user WHERE role = :role', ['role' => 'admin']);
【参数必须是值,不能是字段名或表名】比如ORDER BY ?会当成字符串字面量处理,不会生效;动态排序字段得先白名单校验再拼接。
改数据:用Db::execute()获取影响行数
INSERT、UPDATE、DELETE、TRUNCATE这些写操作,必须走Db::execute()。它不返回数据,只告诉你“成功改了几行”。
Db::execute('UPDATE user SET last_login = NOW() WHERE id = ?', [123]);
批量插入也一样:Db::execute('INSERT INTO log (uid, action, ip) VALUES (?, ?, ?), (?, ?, ?)', [1, 'login', '192.168.1.1', 2, 'logout', '192.168.1.2']);
如果误用Db::query执行UPDATE,你会拿到一个空数组[],而实际SQL已经执行了——这极易造成“以为没改成功”的假象,埋下线上隐患。
安全绑定:值用占位符,表/字段名必须白名单校验
方法一:问号占位符(ThinkPHP 6+原生支持)
Db::query("SELECT * FROM {$table} WHERE name LIKE ? AND status = ?", ["%{$kw}%", 1]);
方法二:命名占位符(推荐,语义更明确)
Db::execute("UPDATE {:table} SET content = :content WHERE id = :id", ['content' => $text, 'id' => $id]);
⚠️注意:{:table}这种写法是ThinkPHP的表名占位语法,但【必须配合白名单校验】,否则攻击者可传入user; DROP TABLE admin--注入整条语句。
正确做法是:$allowedTables = ['user', 'order', 'log']; if (!in_array($table, $allowedTables)) { throw new \Exception('非法表名'); }
事务中执行原生SQL:确保可回滚的关键步骤
第一步:调用Db::startTrans()开启事务
第二步:连续执行Db::query()或Db::execute(),每一步都检查返回值或用try-catch捕获异常
第三步:全部成功则Db::commit(),任一失败则Db::rollback()
特别注意:CREATE TEMPORARY TABLE、SET @var=1、ALTER TABLE等语句在MySQL中不参与事务,哪怕写在startTrans()之后,rollback()也无法撤销它们——这类语句禁止放入事务块。
Db::execute("INSERT INTO user (name) VALUES ('test')"); // 正常事务语句
Db::execute("CREATE TEMPORARY TABLE tmp_user AS SELECT * FROM user"); // ⚠️不可回滚,立刻移出事务
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











