💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## `Mix\Database\PDOConnection` 组件 该组件用于 MySQL 等关系型数据库的操作,语法简单明了,且具有独特的查询构造方式,可构造任何复杂的SQL。 >[success] 该组件基于 PDO 扩展,[语句预处理](http://php.net/manual/zh/pdo.prepared-statements.php) 将帮助你免于SQL注入攻击。 | 类 | 调用 | 连接方式 | | --- | --- | --- | | Mix\Database\PDOConnection | app()->db | 短连接 | ## 使用方法 ### 获取连接 - 同步模式 ``` $db = app()->db; ``` - 协程模式 > 通过连接池组件获取。 ``` $db = app()->dbPool->getConnection(); $db->release(); // 不手动释放的连接不会归还连接池,会在析构时丢弃 ``` ### 插入 ~~~ $data = [ 'name' => 'xiaoliu', 'content' => 'hahahaha', ]; $success = $db->insert('post', $data)->execute(); // 获得刚插入数据的id $insertId = $db->getLastInsertId(); ~~~ ### 批量插入 ~~~ $data = [ ['name' => 'xiaoliu', 'content' => 'hahahaha'], ['name' => 'xiaoliu', 'content' => 'hahahaha'], ['name' => 'xiaoliu', 'content' => 'hahahaha'], ['name' => 'xiaoliu', 'content' => 'hahahaha'], ]; $success = $db->batchInsert('post', $data)->execute(); // 获得受影响的行数 $affectedRows = $db->getRowCount(); ~~~ ### 更新 常规更新: ~~~ $set = [ 'num' => 2, 'name' => 'xiaoliu2', ]; $where = [ ['id', '=', 23], ]; $success = $db->update('post', $set, $where)->execute(); // 获得受影响的行数 $affectedRows = $db->getRowCount(); ~~~ >[success] mix-database >= v2.0.2 更新 / 删除可支持 where 的各种 OR / AND / IN / NOT IN / BETWEEN / NOT BETWEEN 组合,与 QueryBuilder 使用方式相同,如:$where = [['id', '=', 1], ['or', ['id', '=', 2]]]; 自增、自减: ~~~ $set = [ 'num' => ['+', 2], 'num1' => ['-', 1], ]; $where = [ ['id', '=', 23], ]; $success = $db->update('post', $set, $where)->execute(); // 获得受影响的行数 $affectedRows = $db->getRowCount(); ~~~ ### 删除 ~~~ $where = [ ['id', '=', 23], ]; $success = $db->delete('post', $where)->execute(); // 获得受影响的行数 $affectedRows = $db->getRowCount(); ~~~ ### 查询 >[danger] mix-database >= v2.0.4 开始 `createCommand `方法修改为更短的 `prepare`,在 < v2.1 框架会保留兼容性。 #### 执行原生 `SQL` >[info] 请不要直接把参数拼接在 SQL 内执行,带参数的 SQL 请使用参数绑定。 ~~~ $rows = $db->prepare("SELECT * FROM `post`")->queryAll(); ~~~ #### 参数绑定 普通参数绑定: ~~~ $sql = "SELECT * FROM `post` WHERE id = :id AND name = :name"; $rows = $db->prepare($sql)->bindParams([ 'id' => 28, 'name' => 'xiaoliu', ])->queryOne(); ~~~ `IN`、`NOT IN` 数组参数绑定: > `PDO` 扩展是不支持绑定数组参数的,所以 WHERE IN 都只能直接 `implode(', ',$array)` 拼接到 SQL 里面,MixPHP 帮你做了这一步,所以只需像下面这样使用。 ~~~ $sql = "SELECT * FROM `post` WHERE id IN (:id)"; $rows = $db->prepare($sql)->bindParams([ 'id' => [28, 29, 30], ])->queryAll(); ~~~ #### 查询组合 >[success] mix-database >= v2.0.2 可使用 QueryBuilder 替代该功能处理常用 SQL 的生成,而只在复杂 SQL 时使用该方法。 MixPHP 推崇原生 SQL 查询数据库,但由于原生 SQL 在动态 Where 时,做参数绑定会导致逻辑有些复杂,所以 MixPHP 封装了一个查询组合的功能,方便动态控制 Where 与 自动参数绑定。 用户可将整个 SQL 拆分为多个部分,每个部分可选择使用下例两个参数: - `params` 字段内的值会绑定到对应的sql中。 - `if` 字段的值为 false 时,该段 SQL 会丢弃。 常用查询组合: ~~~ $rows = $db->prepare([ ['SELECT * FROM `post`'], ['WHERE id = :id AND name = :name ORDER BY id ASC', 'params' => [ 'id' => $this->id, 'name' => $this->name, ], ], ])->queryAll(); ~~~ 动态 Where 查询组合: ~~~ $rows = $db->prepare([ ['SELECT * FROM `post` WHERE 1 = 1'], ['AND id = :id', 'params' => ['id' => $this->id], 'if' => isset($this->id)], ['AND name = :name', 'params' => ['name' => $this->name], 'if' => isset($this->name)], ['ORDER BY `post`.id ASC'], ])->queryAll(); ~~~ >[info] WHERE 1 = 1 是一个小技巧,能避免没有 Where 时 SQL 错误的情况出现。 更复杂的查询组合,包含了: - 动态 Join - 动态 Where - 分页 ~~~ $rows = $db->prepare([ ['SELECT *'], ['FROM `post`'], [ 'INNER JOIN `user` ON `user`.id = `post`.id', 'if' => isset($this->name), ], ['WHERE 1 = 1'], [ 'AND `post`.id = :id', 'params' => ['id' => $this->id], 'if' => isset($this->id), ], [ 'AND `user`.name = :name', 'params' => ['name' => $this->name], 'if' => isset($this->name), ], ['ORDER BY `post`.id ASC'], ['LIMIT :offset, :rows', 'params' => ['offset' => ($this->currentPage - 1) * $this->perPage, 'rows' => $this->perPage]], ])->queryAll(); ~~~ ### 使用 MySQL 函数、存储过程 ``` $db = $db; $ret = $db->prepare('select :uuid')->bindParams([ 'uuid' => $db::raw('uuid()'), ])->queryAll(); $ret = $db->batchInsert('test', [ ['text' => 'aaa', 'created_at' => $db::raw('CURRENT_TIMESTAMP()'), 'uuid' => $db::raw('uuid()')], ['text' => 'bbb', 'created_at' => $db::raw('CURRENT_TIMESTAMP()'), 'uuid' => $db::raw('uuid()')], ])->execute(); ``` ### 查询返回结果集 返回多行,每行都是列名和值的关联数组。 > 没有结果返回空数组。 ~~~ $rows = $db->prepare("SELECT * FROM `post`")->queryAll(); ~~~ 返回一行 (第一行)。 > 没有结果返回 false。 ~~~ $row = $db->prepare("SELECT * FROM `post` WHERE id = 28")->queryOne(); ~~~ 返回一列。 > 没有结果返回空数组。 ~~~ // 第一列 $titles = $db->prepare("SELECT title FROM `post`")->queryColumn(); // 第二列 $titles = $db->prepare("SELECT * FROM `post`")->queryColumn(1); ~~~ 返回一个标量值。 > 如果该查询没有结果则返回 false。 ~~~ $count = $db->prepare("SELECT COUNT(*) FROM `post`")->queryScalar(); ~~~ 返回一个原生结果集 `PDOStatement` 对象。 > 通常在查询大量结果时,为了避免内存溢出时使用。 ~~~ $statement = $db->prepare("SELECT * FROM `post`")->query(); while ($item = $statement->fetch()) { var_dump($item); } ~~~ ### 返回 SQL 语句 `PDO` 扩展是无法获取最近执行的 SQL 的,所以这个功能是 MixPHP 通过参数构建出来的,这个在调试时是非常好用的功能。 ~~~ // 最新用法 $sql = $db->getLastSql(); // mix-database < v2.0.4 (在v2.1将只支持上面的用法) $sql = $db->getRawSql(); ~~~ ### 返回 SQL 日志 返回一个数组,包含 sql, bindings, time 三个字段。 ~~~ // mix-database >= v2.0.4 $sql = $db->getLastLog(); ~~~ ### 事务 手动事务: ~~~ $db->beginTransaction(); try { $db->insert('test', [ 'text' => '测试测试', ])->execute(); $db->commit(); } catch (\Exception $e) { $db->rollback(); throw $e; } ~~~ 自动事务:等同于上面的手动事务。 ~~~ $db->transaction(function () { $db->insert('test', [ 'text' => '测试测试', ])->execute(); }); ~~~