经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
PHP中使用PDO操作事务的一些小测试
来源:cnblogs  作者:硬核项目经理  时间:2021/6/21 10:12:14  对本文有异议

关于事务的问题,我们就不多解释了,以后在学习 MySQL 的相关内容时再深入的了解。今天我们主要是对 PDO 中操作事务的一些小测试,或许能发现一些比较好玩的内容。

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

首先,相信只要是学过一点点的 MySQL 相关知识的人都知道,在 MySQL 中常用的两种表类型就是 InnoDB 和 MyISAM 这两种类型。当然,我们今天也不讲它们全部的区别,但有一个区别是最明显的,那就是 MyISAM 不支持事务。那么,如果我们在 PDO 操作中对 MyISAM 进行事务操作会怎么样呢?

  1. // myisam
  2. try {
  3. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  4. $pdo->beginTransaction();
  5. $pdo->exec("insert into tran_myisam (name, age) values ('Joe', 12)");
  6. $pdo->exec("insert into tran_myisam2 (name, age) values ('Joe', 12, 33)");
  7. // sleep(30);
  8. $pdo->commit();
  9. } catch (Exception $e) {
  10. $pdo->rollBack();
  11. echo "Failed: " . $e->getMessage(), PHP_EOL;
  12. }

tran_myisam 和 tran_myisam2 表都是 MyISAM 类型的表,在这段代码中,我们故意写错了 tran_myisam2 的插入语句,让它走到 catch 中。实际执行的结果是,报错信息正常输出,tran_myisam 表的数据也被插入了。也就是说,针对 MyISAM 表的事务操作是没有效果的。当然,PDO 也不会主动报错,如果我们让第二条 SQL 语句也是正常语句的话,PDO 只会正常执行结束,不会有任何的错误或者提示信息。

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

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

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

假设我们忘写了 commit() ,同时也没有报错,这条语句会执行成功吗?就像下面这段代码一样。

  1. try {
  2. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  3. $pdo->beginTransaction();
  4. $pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)");
  5. $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12)");
  6. // 忘记写 $pdo->commit(); 了
  7. } catch (Exception $e) {
  8. $pdo->rollBack();
  9. echo "Failed: " . $e->getMessage(), PHP_EOL;
  10. }

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

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

同样的,在上一个问题的基础上我们再继续延伸。如果有两个事务依次执行,第一个事务没有提交,没有回滚,那么下一个事务还能执行吗?

  1. // innodb
  2. try {
  3. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  4. $pdo->beginTransaction();
  5. $pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)");
  6. $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12)");
  7. // 忘记写 $pdo->commit(); 了
  8. } catch (Exception $e) {
  9. $pdo->rollBack();
  10. echo "Failed: " . $e->getMessage(), PHP_EOL;
  11. }
  12. // innodb
  13. try {
  14. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  15. $pdo->beginTransaction();
  16. $pdo->exec("insert into tran_innodb (name, age) values ('BW', 12)");
  17. $pdo->exec("insert into tran_innodb2 (name, age) values ('BW', 12)");
  18. // sleep(30);
  19. $pdo->commit();
  20. } catch (Exception $e) {
  21. $pdo->rollBack();
  22. echo "Failed: " . $e->getMessage(), PHP_EOL; // Failed: There is already an active transaction
  23. }

我们可以看到,第二段事务直接就报错了,内容是:“这里有一个已经存在的活动事务”。也就是说如果上一个事务没有提交没有回滚的话,第二个事务是无法执行的。

总结

今天我们只是学习并测试了几个事务相关的小问题,但问题虽小却有可能带来严重的线上事故,大家在开发的时候一定要小心。关于事务的详细内容在将来深入学习 MySQL 的时候我们再好好研究。

测试代码:

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

参考文档:

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

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

原文链接:http://www.cnblogs.com/zyblog-coder/p/14903663.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号