0x00 前言
用久了 Laravel ORM 之后真的觉得通过 PDO 操作数据库的方式真的是弱爆了,但是作为基础知识还是要了解一下的。万一面试被搞到哑口无言岂不是白白错过工作机会/(ㄒoㄒ)/~~,所以还是决定整理一下关于 PDO 操作的常识。其实 PDO 的核心其实就只有三个类 PDO
、PDOStatement
和 PDOException
,三者分别提供:数据库的连接和SQL语句的执行;返回的结果集处理;出错的异常。所以 PDO 基本使用还是很容易掌握的 O(∩_∩)O 哈哈。
0x01 PDO 类
首先我们看个 PDO 连接数据库并执行 SQL 语句的基本示例:
1 | $dsn = 'mysql:host=127.0.0.1:3306;dbname=test'; |
构造 PDO 类需要四个参数分别是 DSN(数据源)、数据库用户名、数据库密码、连接选项(可选)。数据源的基本格式如下:
<数据库驱动>:host=<数据库主机名>[:数据库端口];dbname=<数据库名>
MySQL的参考数据源:mysql:host=127.0.0.1:3306;dbname=test
重要方法
exec
执行一条的 SQL 语句并返回受影响行数,注意:该方法执行 SELECT 语句只会返回 0 。
query
执行一条的 SQL 语句并返回一个 PDOStatement 对象。示例:
1 | $select = "SELECT * FROM `posts`;"; |
PDOStatement 对象可以理解为「结果集对象」,通过该对象的方法我们可以获取到 SQL 语句的查询结果。
prepare
准备要执行的SQL语句并返回一个 PDOStatement 对象。该函数主要应用为 预处理语句与存储过程。
事务相关:beginTransaction / rollBack / commit / inTransaction
beginTransaction
:开启一个事务,同时关闭自动提交模式即将连接选项中的 PDO::ATTR_AUTOCOMMIT
设置为 false
。
rollBack
:回滚由 PDO::beginTransaction() 发起的当前事务。如果没有事务激活,将抛出一个 PDOException 异常。如果数据库被设置成自动提交模式,此函数(方法)在回滚事务之后将恢复自动提交模式。注意:包括 MySQL 在内的一些数据库, 当在一个事务内有类似删除或创建数据表等 DLL 语句时,会自动导致一个隐式地提交。隐式地提交将无法回滚此事务范围内的任何更改。
commit:提交一个事务,数据库连接返回到自动提交模式直到下次调用 PDO::beginTransaction() 开始一个新的事务为止。
inTransaction:检查驱动内的一个事务当前是否处于激活。此方法仅对支持事务的数据库驱动起作用。
关于自动提交模式,在实例化 PDO 对象或 PDO 对象的 setAttribute 方法都可以设置 PDO::ATTR_AUTOCOMMIT
选项,该选项默认为 true
,即自动提交单独的语句。
事务相关实例代码:
1 | $pdo->beginTransaction(); |
1 | $pdo->beginTransaction(); |
1 | $something = false; |
错误模式
PDO 实例对象的 setAttribute 方法可以设置 PDO::ATTR_ERRMODE
选项改变当 PDO 出错时的错误处理方式,包括 PDO::ERRMODE_SILENT
、PDO::ERRMODE_WARNING
和 PDO::ERRMODE_EXCEPTION
。详细可见 PDO 错误与错误处理。
0x02 PDOStatement 类
PDOStatement 实例可以看做是结果集,即查询结果集合的对象。最主要的功能是参数绑定和获取返回结果数据。下面给出个简单的示例,详细使用方法请看 官方手册。
1 | $statement = $pdo->prepare("SELECT `title`, `author` FROM `posts`"); |
bindParam 和 bindValue 的区别
bindParam 的作用是将变量的引用绑定到预编译的 SQL 语句中,当绑定的变量值改变时 SQL 语句随之改变。示例如下:
1 | $statement = $pdo->prepare("INSERT INTO `posts` (`id`, `title`, `author`) VALUES (:id, :title, :author)"); |
警告:由于 bindParam 是绑定的是变量的引用,所以在 foreach 中会出现意料之外的 BUG。示例如下:
1 | $data = [':title' => 'title', ':author' => 'author']; |
为何 title
列的值会变成 author
呢?原因是 foreach
在循环过程中 $val
变量的值在不断的变化,当循环结束后 $val
的值即为数组中最后一个元素的值,而 bindParam 方法绑定的是引用而不是值,所以此时所有的占位符绑定的都是循环结束后的 $val
变量值,因此就有了这个结果。 解决这个问题我们可以用 bindValue 方法实现。
bindValue 的作用是绑定值到预编译的 SQL 语句中,一经绑定 SQL 语句就固定不变。示例如下:
1 | $data = [':title' => 'title', ':author' => 'author']; |
这样就解决了这个问题,当然我们还可以在 foreach
中使用引用的方式解决这个问题,但是不推荐。示例如下:
1 | $data = [':title' => 'title', ':author' => 'author']; |
0x03 总结
PDO 的使用不算难,因为比起 ORM 来说封装程度不算高所以学起来也简单。最主要掌握建立连接、事务的使用、SQL 语句查询、预编译语句的参数绑定、获取数据的格式和错误处理等就可以了。遇到问题和一些细节的地方还是推荐查 官方手册 。