如何实现4个mysqli查询任意失败时取消所有数据插入
解决多插入语句的原子性问题
嘿,你遇到的这个问题正好是数据库事务要解决的核心场景——我们需要让这4条插入操作成为一个原子单元:要么全部成功写入数据库,要么有任何一条失败就全部撤销,不会留下部分插入的数据。
为什么当前代码会出问题?
MySQL默认是「自动提交」模式,每执行一条INSERT语句,数据库就会立刻把数据持久化到磁盘。所以如果前两条成功了,第三条失败,前两条的数据已经留在库里了,没法撤销。
解决方案:使用数据库事务
我们可以通过手动控制事务来实现原子性,步骤如下:
- 关闭自动提交模式
- 开启事务
- 依次执行所有插入语句,逐个检查执行结果
- 如果所有语句都成功,就提交事务(把所有修改持久化)
- 如果任何一条失败,就回滚事务(撤销所有已经执行的修改)
修改后的代码示例
// 先关闭自动提交 mysqli_autocommit($connection, false); // 标记是否所有操作都成功 $all_success = true; // 执行第一条插入,检查结果 $datastok = mysqli_query($connection,"INSERT into stok (Kod_Barang, Kod_Rak, Harga, Tarikh_Jual) VALUES ('$Kod_Barang','$Kod_Rak','$Harga','$Tarikh_Jual')"); if (!$datastok) { echo "Stok插入失败: " . mysqli_error($connection); $all_success = false; } // 前面成功才继续执行后续语句 if ($all_success) { $databarang = mysqli_query($connection,"INSERT into barang (Kod_Barang, Nama_Barang, Bil_Barang) VALUES ('$Kod_Barang','$Nama_Barang','$Bil_Barang')"); if (!$databarang) { echo "Barang插入失败: " . mysqli_error($connection); $all_success = false; } } if ($all_success) { $datalokasi = mysqli_query($connection,"INSERT into lokasi (Kod_Rak, Jenis_Barang) VALUES ('$Kod_Rak', '$Jenis_Barang')"); if (!$datalokasi) { echo "Lokasi插入失败: " . mysqli_error($connection); $all_success = false; } } if ($all_success) { $datatarikh = mysqli_query($connection,"INSERT into tarikh (Nama_Barang, Tarikh_Beli) VALUES ('$Nama_Barang', '$Tarikh_Beli')"); if (!$datatarikh) { echo "Tarikh插入失败: " . mysqli_error($connection); $all_success = false; } } // 根据结果提交或回滚 if ($all_success) { mysqli_commit($connection); echo "所有数据插入成功!"; } else { mysqli_rollback($connection); echo "插入失败,已撤销所有操作!"; } // 恢复自动提交(可选,根据后续业务逻辑调整) mysqli_autocommit($connection, true);
重要注意事项
- 存储引擎支持:你的表必须使用
InnoDB存储引擎(MySQL默认是这个,但老项目可能用不支持事务的MyISAM),可以用SHOW CREATE TABLE stok;命令查看表的存储引擎。 - SQL注入风险:当前代码直接把用户输入拼接到SQL语句里,存在严重的SQL注入漏洞!建议改用预处理语句,示例如下(以第一条插入为例):
$stmt = mysqli_prepare($connection, "INSERT into stok (Kod_Barang, Kod_Rak, Harga, Tarikh_Jual) VALUES (?, ?, ?, ?)"); mysqli_stmt_bind_param($stmt, "ssds", $Kod_Barang, $Kod_Rak, $Harga, $Tarikh_Jual); $datastok = mysqli_stmt_execute($stmt);
- 错误处理:不要用
or die(),因为它会直接终止脚本,导致无法执行回滚操作,一定要手动判断每个语句的返回值。
内容的提问来源于stack exchange,提问作者MichaelSWS
相关产品推荐
相关产品推荐

