关于事务的问题,我们就不多解释了,以后在学习 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

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

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

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

B站ID:482780532

最新文章

  1. 关于GC和析构函数的一个趣题
  2. Android手机如何通过USB共享网络给Mac?
  3. JavaEE基础(十九)/异常和File
  4. HBase简介(很好的梳理资料)
  5. 普通用户从非80端口启动tomcat,通过端口转发监听80端口
  6. 小结OC中Retain cycle(循环引用)
  7. ubuntu中安装eclipse
  8. Learning Ionic中文版本
  9. 上海2017QCon个人分享总结
  10. 深入探索.NET框架内部了解CLR如何创建运行时对象
  11. Zypper常用命令
  12. SAP基础:定位点运算
  13. [matlab] 15.罚函数降维
  14. semantic ui框架学习笔记三
  15. python自动化开发-[第十六天]-bootstrap和django
  16. css3 特效拓展 画个安卓机器人
  17. GBT 31000-2015 社会治安综合治理基础数据规范 数据项 编码
  18. 安装 kubernetes v1.11.1
  19. MySQL错误[ERR] 1064 - You have an error in your SQL syntax;
  20. 专业实训题目需求分析(3D推箱子)

热门文章

  1. tomcat服务监控分析及自启
  2. Servelt&&JSP进阶
  3. 题解 Emotional Flutter
  4. Jsp:taglib实现
  5. Node.js & Kubernetes Graceful Shutdown
  6. 前端云原生,以 Kubernetes 为基础设施的高可用 SSR(Vue.js) 渲染微服务初探(开源 Demo)
  7. 写webpack插件报警告Tapable.plugin is deprecated. Use new API on .hooks instead解决方案,webpack4插件新写法
  8. 如何攻击Java Web应用
  9. PXC 5.7.14 安装部署
  10. golang 模板 html/template与text/template