如何确保两个INSERT SQL语句均执行成功?解决表单提交时用户与公司数据原子性插入问题
解决两个表原子插入问题:使用数据库事务
你的问题核心是缺乏原子性操作——当前代码里每个INSERT执行后会自动提交到数据库,导致一个成功另一个失败时,已成功的操作无法撤回。解决这个问题的关键是用数据库事务,把两个插入操作包裹在一个事务中,确保它们要么全部成功提交,要么全部失败回滚。
具体调整思路
- 开启事务:关闭PDO的自动提交(默认开启),启动一个事务会话。
- 执行所有操作:依次执行两个插入语句,不中途提交。
- 判断结果:如果两个操作都执行成功,就提交事务;如果任何一个失败,就回滚到事务开始前的状态。
- 异常处理:建议将PDO的错误模式设置为抛出异常,这样能更方便地捕获执行过程中的错误。
修改后的代码示例
// 先设置PDO错误模式为异常(推荐,方便捕获错误) $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 关闭自动提交(可选,beginTransaction()会自动关闭) $dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, false); try { // 开始事务 $dbh->beginTransaction(); // 执行user表插入 $sqlUser = "INSERT INTO user (name, email, password) VALUES (:username, :email, :password)"; $stmtUser = $dbh->prepare($sqlUser); // 绑定参数(这里替换成你的实际绑定逻辑) $stmtUser->bindParam(':username', $username); $stmtUser->bindParam(':email', $email); $stmtUser->bindParam(':password', $password); $stmtUser->execute(); // 执行company表插入 $sqlCompany = "INSERT INTO company (title, number, address) VALUES (:title, :number, :address)"; $stmtCompany = $dbh->prepare($sqlCompany); // 绑定参数(替换成你的实际绑定逻辑) $stmtCompany->bindParam(':title', $title); $stmtCompany->bindParam(':number', $number); $stmtCompany->bindParam(':address', $address); $stmtCompany->execute(); // 两个操作都成功,提交事务 $dbh->commit(); echo "用户和公司信息都注册成功!"; } catch (PDOException $e) { // 任何一步出错,回滚事务 $dbh->rollBack(); echo "注册失败:" . $e->getMessage(); } // 清理语句对象 unset($stmtUser, $stmtCompany);
关键说明
- 事务的原子性:
beginTransaction()启动事务后,所有后续的数据库操作都不会立即写入磁盘,直到调用commit()才会一次性提交;如果中途出错,rollBack()会撤销所有未提交的操作,恢复到事务开始前的状态。 - 异常模式的重要性:设置
ERRMODE_EXCEPTION后,任何PDO操作失败都会抛出PDOException,这样我们能在catch块中统一处理错误并回滚,避免手动检查每个execute()的返回值。 - 避免嵌套执行:原来的代码在第一个插入成功后才执行第二个,改成事务包裹后,两个操作是平级的,只要有一个失败就会触发回滚。
内容的提问来源于stack exchange,提问作者NeonSmash




