## `Pdo` 组件 Pdo 组件用于 MySQL 等关系型数据库的操作,语法简单明了,且具有独特的查询构造方式,可构造任何复杂的SQL。 >[success] 该组件基于 pdo 扩展,[语句预处理](http://php.net/manual/zh/pdo.prepared-statements.php) 将帮助你免于SQL注入攻击。 | 类 | 调用 | 运行环境 | 连接方式 | | --- | --- | --- | --- | | mix\client\Pdo | \Mix::app()->rdb | ALL | 短连接 | ## 组件配置 App配置文件中,该组件的默认配置如下: ~~~ // 数据库 'rdb' => [ // 类路径 'class' => 'mix\client\Pdo', // 数据源格式 'dsn' => 'mysql:host=127.0.0.1;port=3306;charset=utf8;dbname=test', // 数据库用户名 'username' => 'root', // 数据库密码 'password' => '', // 设置PDO属性: http://php.net/manual/zh/pdo.setattribute.php 'attribute' => [ // 设置默认的提取模式: \PDO::FETCH_OBJ | \PDO::FETCH_ASSOC \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, ], ], ~~~ ## 插入 ~~~ $data = [ 'name' => 'xiaoliu', 'content' => 'hahahaha', ]; $success = \Mix::app()->rdb->insert('post', $data)->execute(); // 获得刚插入数据的id $insertId = \Mix::app()->rdb->getLastInsertId(); ~~~ ## 批量插入 ~~~ $data = [ ['name' => 'xiaoliu', 'content' => 'hahahaha'], ['name' => 'xiaoliu', 'content' => 'hahahaha'], ['name' => 'xiaoliu', 'content' => 'hahahaha'], ['name' => 'xiaoliu', 'content' => 'hahahaha'], ]; $success = \Mix::app()->rdb->batchInsert('post', $data)->execute(); // 获得受影响的行数 $affectedRows = \Mix::app()->rdb->getRowCount(); ~~~ ## 更新 ~~~ $set = [ 'id' => 15, 'name' => 'xiaoliu2', ]; $where = [ ['id', '=', 23], ['name', '=', 'xiaoliu'], ]; $success = \Mix::app()->rdb->update('post', $set, $where)->execute(); // 获得受影响的行数 $affectedRows = \Mix::app()->rdb->getRowCount(); ~~~ ## 删除 ~~~ $success = \Mix::app()->rdb->delete('post', [['id', '=', 15]])->execute(); // 获得受影响的行数 $affectedRows = \Mix::app()->rdb->getRowCount(); ~~~ ## 查询 ### 字符串构建查询 >[danger] 请不要直接把参数拼接在 SQL 内执行,带参数的 SQL 请使用参数绑定。 ~~~ $rows = \Mix::app()->rdb->createCommand("SELECT * FROM `post`")->queryAll(); ~~~ ### 参数绑定 ~~~ $sql = "SELECT * FROM `post` WHERE id = :id AND name = :name"; $rows = \Mix::app()->rdb->createCommand($sql)->bindParams([ 'id' => 28, 'name' => 'xiaoliu', ])->queryOne(); ~~~ ### WHERE IN 参数绑定 `PDO` 扩展是不支持绑定数组参数的,所以 WHERE IN 都只能直接 `implode(', ',$array)` 拼接到 SQL 里面,MixPHP 帮你做了这一步,所以只需像下面这样使用。 ~~~ $sql = "SELECT * FROM `post` WHERE id IN (:id)"; $rows = \Mix::app()->rdb->createCommand($sql)->bindParams([ 'id' => [28, 29, 30], ])->queryAll(); ~~~ ### 数组构建查询 >[success] 官方推荐使用该方法构建复杂的长 SQL,因为自动完成了参数绑定,且条件可控,还拥有很好的可读性。 - `params` 字段内的值会绑定到对应的sql中。 - `if` 字段的值为false时,该段sql会丢弃。 常用查询的构建: ~~~ $rows = \Mix::app()->rdb->createCommand([ ['SELECT * FROM `post`'], ['WHERE id = :id AND name = :name', 'params' => ['id' => $this->id, 'name' => $this->name]], ])->queryOne(); ~~~ 复杂查询的动态构建,包含了: - 动态 Join - 动态 Where - 自动参数绑定 - 分页 - `WHERE 1 = 1` 是一个小技巧,当 WHERE 子句的 if 全部为 false 时,WHERE 等于没有设置条件。 ~~~ $rows = \Mix::app()->rdb->createCommand([ ['SELECT *'], ['FROM `post`'], [ 'INNER JOIN `user` ON `user`.id = `post`.id', 'if' => !is_null($this->name), ], ['WHERE 1 = 1'], [ 'AND `post`.id = :id', 'params' => ['id' => $this->id], 'if' => !is_null($this->id), ], [ 'AND `user`.name = :name', 'params' => ['name' => $this->name], 'if' => !is_null($this->name), ], ['ORDER BY `post`.id ASC'], ['LIMIT :offset, :rows', 'params' => ['offset' => ($this->currentPage - 1) * $this->perPage, 'rows' => $this->perPage]], ])->queryAll(); ~~~ ## 查询返回结果集 - 返回多行,每行都是列名和值的关联数组。 - 如果该查询没有结果则返回空数组。 ~~~ $rows = \Mix::app()->rdb->createCommand("SELECT * FROM `post`")->queryAll(); ~~~ - 返回一行 (第一行)。 - 如果该查询没有结果则返回 false。 ~~~ $row = \Mix::app()->rdb->createCommand("SELECT * FROM `post` WHERE id = 28")->queryOne(); ~~~ - 返回一列。 - 如果该查询没有结果则返回空数组。 ~~~ // 第一列 $titles = \Mix::app()->rdb->createCommand("SELECT title FROM `post`")->queryColumn(); // 第二列 $titles = \Mix::app()->rdb->createCommand("SELECT * FROM `post`")->queryColumn(1); ~~~ - 返回一个标量值。 - 如果该查询没有结果则返回 false。 ~~~ $count = \Mix::app()->rdb->createCommand("SELECT COUNT(*) FROM `post`")->queryScalar(); ~~~ ## 返回原生 SQL 语句 `PDO` 扩展是无法获取最近执行的 SQL 的,所以这个功能是 MixPHP 通过参数构建出来的,这个在调试时是非常好用的功能。 ~~~ $sql = \Mix::app()->rdb->getRawSql(); ~~~ ## 事务 手动事务: ~~~ \Mix::app()->rdb->beginTransaction(); try { \Mix::app()->rdb->insert('test', [ 'text' => '测试测试', ])->execute(); \Mix::app()->rdb->commit(); } catch (\Exception $e) { \Mix::app()->rdb->rollback(); throw $e; } ~~~ 自动事务:等同于上面的手动事务。 ~~~ \Mix::app()->rdb->transaction(function () { \Mix::app()->rdb->insert('test', [ 'text' => '测试测试', ])->execute(); }); ~~~