乐趣区

关于php:PHP中使用PDO操作事务的一些小测试

对于事务的问题,咱们就不多解释了,当前在学习 MySQL 的相干内容时再深刻的理解。明天咱们次要是对 PDO 中操作事务的一些小测试,或者能发现一些比拟好玩的内容。

在 MyISAM 上应用事务会怎么样?

首先,置信只有是学过一点点的 MySQL 相干常识的人都晓得,在 MySQL 中罕用的两种表类型就是 InnoDB 和 MyISAM 这两种类型。当然,咱们明天也不讲它们全副的区别,但有一个区别是最显著的,那就是 MyISAM 不反对事务。那么,如果咱们在 PDO 操作中对 MyISAM 进行事务操作会怎么样呢?

// myisam
try {$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->beginTransaction();
    $pdo->exec("insert into tran_myisam (name, age) values ('Joe', 12)");
    $pdo->exec("insert into tran_myisam2 (name, age) values ('Joe', 12, 33)");

    // sleep(30);
    $pdo->commit();} catch (Exception $e) {$pdo->rollBack();
    echo "Failed:" . $e->getMessage(), PHP_EOL;}

tran_myisam 和 tran_myisam2 表都是 MyISAM 类型的表,在这段代码中,咱们成心写错了 tran_myisam2 的插入语句,让它走到 catch 中。理论执行的后果是,报错信息失常输入,tran_myisam 表的数据也被插入了。也就是说,针对 MyISAM 表的事务操作是没有成果的。当然,PDO 也不会被动报错,如果咱们让第二条 SQL 语句也是失常语句的话,PDO 只会失常执行完结,不会有任何的谬误或者提示信息。

// innodb
try {$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->beginTransaction();
    $pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)");
    $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12, 3)");
    // sleep(30);
    $pdo->commit();} catch (Exception $e) {$pdo->rollBack();
    echo "Failed:" . $e->getMessage(), PHP_EOL;}

咱们能够关上 sleep(30); 这行代码的正文,也就是在事务提交前暂停 30 秒,而后在 MySQL 中查看 infomation_schema.INNODB_TRX 表。这个表中显示的就是正在执行中的事务。在 InnoDB 类型的表执行时就能够看到一条事务正在执行的记录,而 MyISAM 类型的表中则不会看到任何信息。

不提交不回滚事务会产生什么?

假如咱们忘写了 commit(),同时也没有报错,这条语句会执行胜利吗?就像上面这段代码一样。

try {$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->beginTransaction();
    $pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)");
    $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12)");

    // 遗记写 $pdo->commit(); 了} catch (Exception $e) {$pdo->rollBack();
    echo "Failed:" . $e->getMessage(), PHP_EOL;}

PHP 会在脚本执行完结后,其实也就是在 $pdo 对象析构时回滚这个事务。也就是说,这里的 SQL 语句是不会执行的。然而,尽量不要这么做,因为在正式环境中,咱们的代码非常复杂,而且不肯定会析形成功。这样的话,可能会有长时间占据的事务存在,最终后果就是会导致 MySQL 的 IPQS 奇高,而且还很难找到起因。所以,在应用事务的时候,肯定要记得 commit() 和 rollBack() 都是咱们的亲兄弟,绝不能落下他们。

上一个事务没有提交没有回滚,下一个事务会执行吗?

同样的,在上一个问题的根底上咱们再持续延长。如果有两个事务顺次执行,第一个事务没有提交,没有回滚,那么下一个事务还能执行吗?

// innodb
try {$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->beginTransaction();
    $pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)");
    $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12)");
    // 遗记写 $pdo->commit(); 了} catch (Exception $e) {$pdo->rollBack();
    echo "Failed:" . $e->getMessage(), PHP_EOL;}

// innodb
try {$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->beginTransaction();
    $pdo->exec("insert into tran_innodb (name, age) values ('BW', 12)");
    $pdo->exec("insert into tran_innodb2 (name, age) values ('BW', 12)");

    // sleep(30);
    $pdo->commit();} catch (Exception $e) {$pdo->rollBack();
    echo "Failed:" . $e->getMessage(), PHP_EOL; // Failed: There is already an active transaction}

咱们能够看到,第二段事务间接就报错了,内容是:“这里有一个曾经存在的流动事务”。也就是说如果上一个事务没有提交没有回滚的话,第二个事务是无奈执行的。

总结

明天咱们只是学习并测试了几个事务相干的小问题,但问题虽小却有可能带来重大的线上事变,大家在开发的时候肯定要小心。对于事务的具体内容在未来深刻学习 MySQL 的时候咱们再好好钻研。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PHP 中应用 PDO 操作事务的一些小测试.php

参考文档:

https://www.php.net/manual/zh/pdo.transactions.php

各自媒体平台均可搜寻【硬核项目经理】

退出移动版