如何在PHP中通过单次按钮点击执行多条预准备SQL语句?
嘿,我来帮你搞定这个单次点击执行两条预准备SQL语句的问题!核心是要用数据库事务把两个操作绑定在一起,确保要么都成功,要么都回滚,绝不能出现“订单插了但库存没扣”或者反过来的混乱情况。下面一步步给你讲具体实现:
解决方案:事务包裹+预准备语句实现原子操作
1. 核心逻辑:用事务保证操作原子性
不管你用什么后端语言(PHP/Java/Python等),流程都是一致的:先开启事务,依次执行两条预准备SQL,最后根据结果提交或回滚。
步骤拆解:
- 开启事务:关闭数据库自动提交,让所有操作暂时存到内存,直到你手动确认提交。
- 查询菜品份值:先从
theProducts表拿到目标菜品的dbProdServing,这是后续两个操作都要用的值。 - 插入订单项:用预准备语句把菜品信息插入
theOrderItems,避免SQL注入。 - 更新库存:同样用预准备语句,从
theInventory的对应菜品库存里扣除刚才拿到的份值。 - 提交/回滚:如果所有步骤都成功,就提交事务把变更写入数据库;只要有一步出错,就回滚到操作前的状态。
2. 前端按钮绑定(JavaScript示例)
给菜品按钮绑定点击事件,触发后端的事务处理接口:
// 假设每个菜品按钮都带了data-dish-id属性存菜品ID document.querySelectorAll('.dish-btn').forEach(btn => { btn.addEventListener('click', async () => { const dishId = btn.dataset.dishId; try { const res = await fetch('/api/add-dish-to-order', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ dishId }) }); const result = await res.json(); if (result.success) { alert('菜品已加入订单,库存已更新!'); // 这里可以加页面刷新/订单列表更新的逻辑 } else { alert(`操作失败:${result.message}`); } } catch (err) { alert('服务器或网络出错啦,请重试'); } }); });
3. 后端实现(PHP+PDO示例)
用PDO处理预准备语句和事务,安全性和可靠性都拉满:
<?php header('Content-Type: application/json'); // 初始化PDO连接 $pdo = new PDO('mysql:host=你的数据库地址;dbname=你的库名', '用户名', '密码'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); try { $pdo->beginTransaction(); // 开启事务 $dishId = json_decode(file_get_contents('php://input'), true)['dishId']; // 1. 查询菜品份值 $stmt = $pdo->prepare('SELECT dbProdServing FROM theProducts WHERE prod_id = ?'); $stmt->execute([$dishId]); $product = $stmt->fetch(PDO::FETCH_ASSOC); if (!$product) throw new Exception('该菜品不存在'); $serving = $product['dbProdServing']; // 2. 先校验库存是否足够(可选但非常建议) $stmt = $pdo->prepare('SELECT dbInventoryAmt FROM theInventory WHERE prod_id = ?'); $stmt->execute([$dishId]); $inventory = $stmt->fetch(PDO::FETCH_ASSOC); if ($inventory['dbInventoryAmt'] < $serving) throw new Exception('库存不足,无法添加'); // 3. 插入订单项(假设当前订单ID存在session中) $orderId = $_SESSION['current_order_id']; $stmt = $pdo->prepare('INSERT INTO theOrderItems (order_id, prod_id, serving_amount) VALUES (?, ?, ?)'); $stmt->execute([$orderId, $dishId, $serving]); // 4. 更新库存 $stmt = $pdo->prepare('UPDATE theInventory SET dbInventoryAmt = dbInventoryAmt - ? WHERE prod_id = ?'); $stmt->execute([$serving, $dishId]); $pdo->commit(); // 提交事务 echo json_encode(['success' => true]); } catch (Exception $e) { $pdo->rollBack(); // 出错就回滚 echo json_encode(['success' => false, 'message' => $e->getMessage()]); } ?>
必看注意事项
- 事务不能少:没有事务的话,一旦中间步骤出错,数据就会不一致,比如订单加了但库存没扣,这会给后续对账带来大麻烦。
- 预准备语句必须用:绝对不能直接拼接SQL字符串,不然会有SQL注入风险,把数据库搞崩都有可能。
- 库存校验要加:虽然你没提,但强烈建议在更新前检查库存是否足够,避免出现负库存的情况,这也是业务逻辑的基本要求。
内容的提问来源于stack exchange,提问作者Jack Phillips
相关产品推荐
相关产品推荐

