关于 PDO 的学习我们告一段落,从这篇文章开始,我们继续学习另外一个 MySQL 扩展,也就是除了 PDO 之外的最核心的 MySQLi 扩展。可以说它的祖先,也就是 MySQL(原始) 扩展是我们很多人刚开始学习 PHP 时连接数据库的入门导师。不过随着时代的变迁,MySQL(原始) 扩展在 PHP7 中已经被彻底废弃了。现在如果想要使用过程式的代码来操作数据库,只能使用 mysqli 扩展了。当然,mysqli 扩展也是支持面向对象式的写法的。
什么是 MySQLi
MySQLi 扩展允许我们访问 MySQL4.1 及以上版本的数据库所提供的功能。它是专门针对于 MySQL 数据库的,不像 PDO 可以通过不同的 dns 来连接不同的数据库。
与 MySQL 和 PDO 的区别与联系
首先,我们还是回顾一下最早的 MySQL 扩展。
- 只面向过程
- 不支持 存储过程 、 多语句执行 、 预处理语句
- PHP7 中已经删除了并且完全不支持
然后是 PDO 。
- 仅支持面向对象方式使用
- 可以连接多种数据库,切换数据库带来的变更少,甚至可能不用修改代码
- 支持 存储过程 、 多语句执行 、 预处理语句
最后就是 MySQLi 。
- 支持面向对象和面向过程两种写法
- 仅支持 MySQL 数据库
- 支持 存储过程 、 多语句执行 、 预处理语句
- 跟随 PHP 及 MySQL 的版本更新,可以更快速地支持更多的 MySQL 高级特性
从它们三个的这些特点来看,MySQL(原始)扩展肯定是不推荐了,就算是老的项目,只要是支持 PDO 或 MySQLi 的 PHP 版本,都应该考虑将数据库的连接转换成这两种方式之一。如果你还在 PHP5 的环境中学习 MySQL(原始)扩展的使用的话,也可以放下了。
而对于 PDO 和 MySQLi 的选择来说,就仁者见仁智者见智了。本身它们其实并没有什么太大的差别,不过现代化的大型框架中基本都会将 PDO 作为默认的数据库连接来进行封装,毕竟它的可移植性可以方便这些通用框架连接不同的数据库。而一些小型的框架或项目中,还是能够见到 MySQLi 的身影。当然,小众并不意味着不好,就像日常开发中,我们很少会在 PHP 环境中使用别的数据库,那么在自己的小项目中完全使用一套 MySQLi 来操作数据库反而更加地方便快捷。同时,老项目如果要切换到 PHP7 版本的话,如果之前使用的是 MySQL(原始)连接的数据库,也能够快速地将 MySQL(原始)的代码很方面地替换到 MySQLi 。
扩展的安装及 MySQL8 需要注意的地方
MySQLi 的扩展是随 PHP 源码一起发布的,我们在编译 PHP 的时候加上 –with-mysqli 就可以了。现在默认的数据库驱动都是使用的 mysqlnd ,libmysql 也已经基本淘汰了。所以在编译时不需要再加上其它的参数,直接进行编译即可。
在连接 MySQL8 的时候需要注意,因为 MySQL8 服务器会默认使用 caching_sha2_password 作为密码的加密。而 PHP7.2.4 之前的版本中的 MySQLi 会使用 mysql_native_password 来对连接密码进行加密,这样就会导致无法连接上数据库。大家可以修改 my.cnf 文件,设置 default_authentication_plugin=mysql_native_password ,让 MySQL8 也使用 mysql_native_password 来加密用户密码。
面向过程式
上文说过,MySQLi 是支持两种写法的,也就是面向对象和面向过程。简单地理解就是一种是 MySQL(原始)扩展的写法,另一种写法是类似于 PDO 的写法。我们先来看看面向过程的写法。
$mysqli = mysqli_connect("localhost", "root", "", "blog_test"); $res = mysqli_query($mysqli, "SELECT * FROM zyblog_test_user"); $row = mysqli_fetch_assoc($res); print_r($row);
是不是感觉 MySQL(原始)扩展的代码要移植过来真的很方便。方法名上全部改成 mysqli_xxx 就可以了。
面向对象式
面向对象式的就有点像 PDO 。我们要先获得一个连接句柄类,然后操作这个类就可以了。
$mysqli = new mysqli("localhost", "root", "", "blog_test"); $res = $mysqli->query("SELECT * FROM zyblog_test_user"); $row = $res->fetch_assoc(); print_r($row);
面向对象和面向过程混用
另外,这两种方式还可以混合使用,不过并不推荐。混合起来使用的话很容易让看代码的人晕头转向。所以,最好还是在一个项目中就坚持使用一种方式。
$mysqli = new mysqli("localhost", "root", "", "blog_test"); $res = mysqli_query($mysqli, "SELECT * FROM zyblog_test_user"); $row = $res->fetch_assoc(); print_r($row);
在这段代码中,我们实例化了一个 mysqli 对象,然后使用面向过程的 mysqli_query() 函数来执行语句,接着又使用面向对象的方式来获取结果集。是不是很乱?但是它是可以正常运行的。
总结
从上面的内容中可以看出,PDO 的特点是支持多种不同类型的数据库,就像 Java 中的 JDBC 一样。而 MySQLi 虽然只支持 MySQL 数据库,但它却可以同时支持面向对象和面向过程两种写法。是我们针对老项目代码进行升级优化的好帮手。同时,它还是现在入门 PHP 学习相关数据库操作的首选。在接下来的文章中,我们将默认只使用 面向对象 式的写法来继续学习 MySQLi 扩展相关的知识。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/4.PHP中的MySQLi扩展学习(一)MySQLi介绍.php
参考文档:
https://www.php.net/manual/zh/mysqli.requirements.php
https://www.php.net/manual/zh/mysqli.installation.php
https://www.php.net/manual/zh/mysqli.overview.php
https://www.php.net/manual/zh/mysqli.quickstart.dual-interface.php