mysqli事务异常未触发catch块:错误SQL无法触发回滚
解决mysqli事务中SQL错误无法触发catch块回滚的问题
问题根源
你遇到的情况是因为mysqli开启了严格错误报告模式(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT),当SQL执行出错时,mysqli_query()会直接抛出mysqli_sql_exception致命异常,而不是返回false,导致你的if(!$sql2)判断根本没机会执行,程序直接终止,无法进入catch块。
解决方案
方案1:保留严格异常模式,直接捕获SQL执行异常
这种方式更简洁,利用mysqli自带的异常抛出机制,直接在外层try块中捕获所有数据库操作异常,然后执行回滚。
示例代码:
// 开启严格错误报告模式(若已开启则保留) mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $con = mysqli_connect("你的主机", "用户名", "密码", "数据库名"); try { // 开启事务 $con->begin_transaction(); // 执行第一个查询 mysqli_query($con, $query); // 执行第二个查询(表名错误会触发异常) mysqli_query($con, $query2); // 所有查询成功,提交事务 $con->commit(); echo "事务执行成功"; } catch (mysqli_sql_exception $e) { // 捕获SQL异常,执行回滚 $con->rollback(); echo "事务回滚,错误信息:" . $e->getMessage(); } catch (Exception $e) { // 捕获其他异常 $con->rollback(); echo "未知错误,事务回滚:" . $e->getMessage(); } finally { // 关闭连接(可选) mysqli_close($con); }
方案2:关闭严格异常模式,手动判断执行结果
如果你更习惯通过返回值判断执行状态,可以关闭严格异常模式,让mysqli_query()在出错时返回false,然后手动抛出异常进入catch块。
示例代码:
// 关闭严格异常模式,仅返回错误而不抛出致命异常 mysqli_report(MYSQLI_REPORT_OFF); $con = mysqli_connect("你的主机", "用户名", "密码", "数据库名"); // 检查连接错误 if (mysqli_connect_errno()) { throw new Exception("数据库连接失败:" . mysqli_connect_error()); } try { $con->begin_transaction(); $sql1 = mysqli_query($con, $query); if (!$sql1) { throw new Exception("第一个查询失败:" . mysqli_error($con)); } $sql2 = mysqli_query($con, $query2); if (!$sql2) { throw new Exception("第二个查询失败:" . mysqli_error($con)); } $con->commit(); echo "事务执行成功"; } catch (Exception $e) { $con->rollback(); echo "事务回滚,错误信息:" . $e->getMessage(); } finally { mysqli_close($con); }
注意事项
- 无论哪种方案,所有数据库操作必须放在try块内部,确保异常能被捕获。
- 使用
begin_transaction()开启事务,避免使用mysqli_query($con, "START TRANSACTION"),前者更符合面向对象写法且兼容性更好。 - 建议优先使用方案1,利用mysqli的异常机制可以减少手动错误判断的代码,逻辑更清晰。
内容的提问来源于stack exchange,提问作者GOURAV JANGID
相关产品推荐
相关产品推荐

