💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## Mix\Database\Connection::class 该类用于 MySQL 等关系型数据库的操作,语法简单明了,且具有独特的查询构造方式,可构造任何复杂的SQL。 >[success] 该类基于 PDO 扩展,[语句预处理](http://php.net/manual/zh/pdo.prepared-statements.php) 将帮助你免于SQL注入攻击 ## 依赖注入配置 - [beans/database.php#L32](https://github.com/mix-php/mix-skeleton/tree/v2.1/manifest/beans/database.php#L32) ## 直接获取连接 除了通过连接池,我们还能直接通过某个依赖配置直接获取连接实例: > 由于 manifest.php 中 Connection::class 的依赖配置并没有设置 name 属性,因此 name = 命名空间 ~~~ /** @var \Mix\Database\Connection $db */ $db = context()->get(\Mix\Database\Connection::class); ~~~ ## 插入 ~~~ $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] 更新 / 删除支持 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(); ~~~ ## 查询 - 执行原生 `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] 可使用 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 函数、存储过程 ``` $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(); // 指定返回对象数组 $rows = $db->prepare("SELECT * FROM `post`")->queryAll(\PDO::FETCH_OBJ); ~~~ 返回一行 (第一行)。 > 没有结果返回 false。 ~~~ // 默认返回数组 $row = $db->prepare("SELECT * FROM `post` WHERE id = 28")->queryOne(); // 指定返回对象 $row = $db->prepare("SELECT * FROM `post` WHERE id = 28")->queryOne(\PDO::FETCH_OBJ); ~~~ 返回一列。 > 没有结果返回空数组。 ~~~ // 第一列 $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(); ~~~ ## 返回 SQL 日志 返回一个数组,包含 sql, bindings, time 三个字段。 ~~~ $sql = $db->getLastLog(); ~~~ ## 事务 手动事务: ~~~ $db->beginTransaction(); try { $db->insert('test', [ 'text' => '测试测试', ])->execute(); $db->commit(); } catch (\Exception $e) { $db->rollback(); throw $e; } ~~~ 自动事务:等同于上面的手动事务,抛出异常时自动回滚。 ~~~ $db->transaction(function () use ($db) { $db->insert('test', [ 'text' => '测试测试', ])->execute(); }); ~~~ ## 长连接超时问题 MySQL 配置文件内的 `interactive_timeout` 与 `wait_timeout` 参数,决定了 sleep 多长时间的连接会被主动 kill,正常情况下是需要用户自己来处理连接超时的问题,但使用该组件,用户不需要处理,组件底层已经帮你处理了。