Yii2 MariaDB事务提交无报错但数据未写入数据库问题排查
问题分析与解决方案
一、事务提交后无数据且未抛异常的原因
Yii的commit()方法默认不会主动抛出异常,仅当数据库返回致命错误时才会触发捕获逻辑。如果事务是被隐式回滚(而非主动报错),代码会顺利走到echo "All good!",但实际数据并未写入。常见场景包括:
- 锁超时/死锁:MariaDB在部分锁冲突场景下仅返回警告,不会抛出致命错误,同时自动回滚事务
- 数据库配置变更:近期调整过
innodb_rollback_on_timeout、transaction_isolation等参数,导致事务行为改变 - 连接复用异常:使用数据库连接池时,复用的连接事务状态异常,导致提交操作无效
- 事务隔离级别冲突:比如
REPEATABLE READ级别下的幻读/锁等待,触发隐式回滚但未返回错误
二、如何捕获事务提交的异常/警告
方案1:全局开启PDO异常模式
在数据库配置文件(config/db.php或config/web.php)中添加PDO异常模式配置,让所有数据库警告转为异常:
'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=your_db', 'username' => 'root', 'password' => '', 'charset' => 'utf8mb4', 'attributes' => [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ], ],
方案2:手动检查事务提交结果
如果不想全局修改配置,可在commit()后手动校验数据库状态:
$tx = Yii::$app->db->beginTransaction(); try { // 业务代码(读写操作) $tx->commit(); // 手动检查数据库警告 $errorInfo = Yii::$app->db->pdo->errorInfo(); if ($errorInfo[0] !== '00000') { throw new \yii\db\Exception($errorInfo[2], $errorInfo[1]); } echo "All good!"; } catch (\Throwable $ex) { $tx->rollback(); echo "Error: " . $ex->getMessage(); }
三、排查与修复事务无效的步骤
- 查看数据库错误日志:搜索MariaDB日志(通常路径
/var/log/mysql/error.log),查找Deadlock found、Lock wait timeout exceeded等关键词,定位具体异常 - 验证事务隔离级别:执行
SELECT @@transaction_isolation;对比历史配置,临时切换为READ COMMITTED测试是否恢复正常 - 重置数据库连接池:若使用连接池,重启应用服务清空连接池,排查连接复用问题
- 简化事务代码:逐步移除事务内的业务逻辑,仅保留基础插入操作,定位导致回滚的代码段
- 检查InnoDB状态:执行
SHOW ENGINE INNODB STATUS;查看是否有挂起事务、锁等待等异常 - 确认账号权限:验证数据库账号的事务、读写权限是否被意外修改
四、临时替代方案(保证数据一致性)
若暂时无法定位根因,可使用Yii的闭包式事务方法,它会自动处理提交/回滚,且在异常模式下会主动抛出错误:
Yii::$app->db->transaction(function($db) { // 业务逻辑代码,自动在事务内执行 // 闭包内抛出异常则自动回滚,否则自动提交 });
内容的提问来源于stack exchange,提问作者nssmart
相关产品推荐
相关产品推荐

