ThinkPHP8学习篇(六):数据库(二)

在数据库操作环节,查询表达式是描述查询条件的核心工具,而链式操作则为复杂查询逻辑的构建提供了流畅且高效的实现方式,二者共同构成了灵活处理数据查询需求的关键支撑。本篇作为数据库系列文章的第二篇,学习核心内容将集中在各类查询表达式(如比较、逻辑、区间等)的语法与应用,以及 ThinkPHP 中常用的链式操作方法(如 where、order、limit 等)的组合使用上。本篇文章将记录 ThinkPHP 数据库查询表达式与链式操作方法的学习过程。

一、查询表达式

1、等于(=)

2、不等于(<>)

[3、[NOT] LIKE: 同sql的 [NOT] LIKE](#3、[NOT] LIKE: 同sql的 [NOT] LIKE)

[4、[NOT] IN: 同sql的 [not] in](#4、[NOT] IN: 同sql的 [not] in)

[5、[NOT] NULL](#5、[NOT] NULL)

6、EXP:表达式

二、链式操作

1、where

1.1、表达式查询

1.2、数组条件

1.3、字符串条件

2、table

3、alias

4、field

4.1、用于查询

4.2、用于写入

5、strict

6、limit

6.1、限制结果数量

6.2、分页查询

7、page

8、order

9、group

10、having

11、join

12、union

13、distinct

14、lock

15、cache

15.1、缓存自动更新

16、cacheAlways

17、fetchSql

18、failException


一、查询表达式

查询表达式支持大部分的SQL查询语法,表达式的使用格式为:

php 复制代码
where('字段名', '查询表达式', '查询条件');

除了 where 方法外,还支持 whereOr,用法是一样的。为了方便查询,大多数的查询表达式都提供了快捷查询方法。

表达式不区分大小写,支持的查询表达式如下表所示:

|----------------------|---------------------|------------------------------|
| 表达式 | 含义 | 快捷查询方法 |
| = | 等于 | |
| <> | 不等于 | |
| > | 大于 | |
| >= | 大于等于 | |
| < | 小于 | |
| <= | 小于等于 | |
| [NOT] LIKE | 模糊查询 | whereLike/whereNotLike |
| [NOT] BETWEEN | (不在)区间查询 | whereBetween/whereNotBetween |
| [NOT] IN | (不在)IN 查询 | whereIn/whereNotIn |
| [NOT] NULL | 查询字段是否(不)是NULL | whereNull/whereNotNull |
| [NOT] EXISTS | EXISTS查询 | whereExists/whereNotExists |
| [NOT] REGEXP | 正则(不)匹配查询(仅支持Mysql) | |
| [NOT] BETWEEN TIME | 时间区间比较 | whereBetweenTime |
| > TIME | 大于某个时间 | whereTime |
| < TIME | 小于某个时间 | whereTime |
| >= TIME | 大于等于某个时间 | whereTime |
| <= | 小于等于某个时间 | whereTime |
| EXP | 表达式查询,支持SQL语法 | whereExp |
| find in set | FIND_IN_SET查询 | whereFindInSet |

接下来一起来看下表达式查询用法示例。

1、等于(=)

php 复制代码
// 查询 user 表中 id=1 的数据
Db::table('user')->where('id', '=', 1)->select();
// 表达式为 "=" 时可以省略,下面的查询与上面的查询等效
Db::table('user')->where('id', 1)->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `id` = 1

2、不等于(<>)

php 复制代码
// 查询 user 表中 id<>1 的数据
Db::table('user')->where('id', '<>', 1)->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `id` <> 1

大于(>)、大于等于(>=)、小于(<)、小于等于(<=)的用法与不等于(<>)的用法相同。

3、[NOT] LIKE: 同sql的 [NOT] LIKE

php 复制代码
// 查询 user 表中 name 字段的值以 zhang 开头的数据
Db::table('user')->where('name', 'like', 'zhang%')->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `name` LIKE 'zhang%'

like 查询支持使用数组作为查询条件:

php 复制代码
// where() 方法中第四个参数指定条件连接方式,默认为 AND
Db::table('user')->where('name', 'like', ['zhang%', 'li%'], 'or')->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  (`name` LIKE 'zhang%' OR `name` LIKE 'li%')

或者使用快捷查询方法 whereLike:

php 复制代码
Db::table('user')->whereLike('name', 'zhang%')->select();
Db::table('user')->whereNotLike('name', 'zhang%')->select();

4、[NOT] IN: 同sql的 [not] in

查询条件支持字符串或者数组:

php 复制代码
// 多个值之间使用 "," 号分隔
Db::table('user')->where('id', 'in', '1,2,3')->select();
// 也可以使用数据进行传值
Db::table('user')->where('id', 'in', [1,2,3])->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `id` IN (1,2,3)

或者使用快捷查询方法:

php 复制代码
Db::table('user')->whereIn('id', [1,2,3])->select();
Db::table('user')->whereNotIn('id', [1,2,3])->select();

5、[NOT] NULL

查询字段是否(不)是 NULL。

php 复制代码
// 查询 user 表中 user 不为空,status 为空的数据
Db::table('user')->where('name', 'not null')
->where('status', 'null')->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `name` IS NOT NULL  AND `status` IS NULL

官方推荐的方式是使用 whereNull 和 whereNotNull 方法查询。

php 复制代码
Db::table('user')->whereNotNull('name')
->whereNull('status')
->select();

6、EXP:表达式

exp 查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。

php 复制代码
Db::table('user')->where('name', 'exp', 'like \'zhang%\'')->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  ( `name` like 'zhang%' )

官方推荐使用 whereExp 方法查询。

php 复制代码
Db::table('user')->whereExp('name', 'like \'zhang%\'')->select();

二、链式操作

数据库提供的链式操作方法,可以有效的提高数据存取的代码清晰度和开发效率,并且支持所有的CURD操作(原生查询不支持链式操作)。

使用方法也很简单,假如我们现在要查询一个 user 表中满足状态为1的前10条记录,并希望按照用户的创建时间排序 ,代码可以这样写:

php 复制代码
use think\facade\Db;

Db::table('user')
    ->where('status', 1)
    ->order('create_time')
    ->limit(10)
    ->select();

这里的 where、order 和 limit 方法就被称为链式操作方法,除了 select 方法必须放到最后一个外(因为select方法并不是链式操作方法),链式操作的方法调用顺序没有先后,例如,下面的代码和上面的等效:

php 复制代码
Db::table('user')
    ->order('create_time')
    ->limit(10)
    ->where('status', 1)
    ->select();

不仅仅是查询方法可以使用链式操作,包括所有的CURD方法都可以使用,例如:

php 复制代码
// 查询 user 表中 id=1 的数据,返回 id,name,email 三个字段的值
Db::table('user')
    ->where('id', 1)
    ->field('id,name,email')
    ->find(); 

// 删除 user 表中 id=1 AND status=1 的数据
Db::table('user')
    ->where('status', 1)
    ->where('id', 1)
    ->delete();

每次 Db 类的静态方法调用是创建一个新的查询对象实例,如果需要多次复用使用链式操作值,可以使用下面的方法。

php 复制代码
$user = Db::table('user');
$user->order('create_time')
    ->where('status', 1)
    ->select();
    
// 会自动带上前面的 where 条件和 order 排序的值    
$user->where('id', '>', 0)->select();

当前查询对象在查询之后仍然会保留链式操作的值,调用 removeOption 方法清空链式操作的值。

php 复制代码
$user = Db::table('user');
$user->order('create_time')
    ->where('status', 1)
    ->select();

// 清空 where 查询条件值 保留其它链式操作   
$user->removeOption('where')
    ->where('id', '>', 0)
    ->select();

系统支持的链式操作方法如下表所示:

|---------------|---------------------|-------------|
| 连贯操作 | 作用 | 支持的参数类型 |
| where* | 用于AND查询 | 字符串、数组和对象 |
| whereOr* | 用于OR查询 | 字符串、数组和对象 |
| whereTime* | 用于时间日期的快捷查询 | 字符串 |
| table | 用于定义要操作的数据表名称 | 字符串和数组 |
| alias | 用于给当前数据表定义别名 | 字符串 |
| field* | 用于定义要查询的字段(支持字段排除) | 字符串和数组 |
| order* | 用于对结果排序 | 字符串和数组 |
| limit | 用于限制查询结果数量 | 字符串和数字 |
| page | 用于查询分页(内部会转换成limit) | 字符串和数字 |
| group | 用于对查询的group支持 | 字符串 |
| having | 用于对查询的having支持 | 字符串 |
| join* | 用于对查询的join支持 | 字符串和数组 |
| union* | 用于对查询的union支持 | 字符串、数组和对象 |
| view* | 用于视图查询 | 字符串、数组 |
| distinct | 用于查询的distinct支持 | 布尔值 |
| lock | 用于数据库的锁机制 | 布尔值 |
| cache | 用于查询缓存 | 支持多个参数 |
| with* | 用于关联预载入 | 字符串、数组 |
| bind* | 用于数据绑定操作 | 数组或多个参数 |
| comment | 用于SQL注释 | 字符串 |
| force | 用于数据集的强制索引 | 字符串 |
| master | 用于设置主服务器读取数据 | 布尔值 |
| strict | 用于设置是否严格检测字段名是否存在 | 布尔值 |
| sequence | 用于设置Pgsql的自增序列名 | 字符串 |
| failException | 用于设置没有查询到数据是否抛出异常 | 布尔值 |
| partition | 用于设置分区信息 | 数组 字符串 |
| replace | 用于设置使用REPLACE方式写入 | 布尔值 |
| extra | 用于设置额外查询规则 | 字符串 |
| duplicate | 用于设置DUPLCATE信息 | 数组 字符串 |

所有的连贯操作都返回当前的模型实例对象(this),其中带 * 标识的表示支持多次调用。

下面我们来看一些常用链式操作方法的说明与使用。

1、where

where 方法可以完成包括普通查询、表达式查询、快捷查询、区间查询、组合查询在内的查询操作。where 方法的参数支持的变量类型包括字符串、数组和闭包。

和 where 方法相同用法的方法还包括 whereOr、whereIn 等一系列快捷查询方法,下面仅以 where 方法为例说明用法。

1.1、表达式查询

表达式查询是官方推荐使用的查询方式。使用格式为上文的查询表达式部分。

php 复制代码
// where 方法可以多次调用,查询条件以 AND 进行连接
Db::table('user')
    ->where('id', '>', 1)
    ->where('name', 'zhangsan')
    ->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `id` > 1  AND `name` = 'zhangsan'

1.2、数组条件

数组方式有两种查询条件类型:关联数组和索引数组。

关联数组主要用于等值AND条件,例如:

php 复制代码
// 传入关联数组作为查询条件,查询条件的方式为 key1=value1 AND key2=value2 ...
Db::table('user')->where([
    'name'  =>  'zhangsan',
    'status'=>  1
])->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  `name` = 'zhangsan'  AND `status` = 1

索引数组方式可以批量设置查询条件,使用方式如下:

php 复制代码
// 传入数组作为查询条件,数组的方式为二维数组,其中每一个数组的内容是:
// [0]:数据库字段,[1]:查询表达式,[2]:查询条件值
Db::table('user')->where([
    ['name', '=', 'zhangsan'],
    ['status', '=', 1]
])->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  (  `name` = 'zhangsan'  AND `status` = 1 )

1.3、字符串条件

whereRaw 方法用于在查询中直接添加原生的SQL条件,适用于一些复杂的查询条件或需要使用数据库特定函数的场景。例如:

php 复制代码
Db::table('user')->whereRaw('age > 18 AND name like \'zhang%\'')->select();
// 生成的SQL语句为:SELECT * FROM `user` WHERE  ( age > 18 AND name like 'zhang%' )

注意:使用字符串查询条件和表达式查询的一个区别在于,不会对查询字段进行避免关键词冲突处理。

为了避免SQL注入风险,whereRaw 支持参数绑定,有两种方式:

  1. 数组绑定

    php 复制代码
    // 使用参数标识符进行占位,类似 ":name" 的形式
    Db::table('user')
        ->whereRaw('age > :age AND name like :name', ['age' => 18, 'name' => 'zhang%'])
        ->select();
  2. 问号(?)占位符

php 复制代码
// 使用 ? 标识符进行占位,数组要传入的值要和 ? 号的位置一致
Db::table('user')
    ->whereRaw('age > ? AND name like ?', [18, 'zhang%'])
    ->select();

2、table

table 方法主要用于指定操作的数据表。一般情况下,操作模型的时候系统能够自动识别当前对应的数据表,所以,使用 table 方法的情况通常是为了:

  • 切换操作的数据表
  • 对多表进行操作

示例

php 复制代码
Db::table('user')->select();
// 也可以在 table 方法中指定数据库,方式为:数据库名称.数据表名称
Db::table('test.user')->select();

需要注意的是 table 方法不会改变数据库的连接,所以要确保当前连接的用户有权限操作相应的数据库和数据表。

如果需要对多表进行操作,可以这样做:

php 复制代码
Db::field('user.name, role.title')  // 查询返回的字段
    ->table('user, role')           // 查询的数据表
    ->select();

为了尽量避免和mysql的关键字冲突,官方建议使用数组方式定义,例如:

php 复制代码
Db::field('user.name, role.title')  // 查询返回的字段
    ->table(['user', 'role'])       // 查询的数据表,也可以以关联数组的方式给出表的别名:['数据表名' => '别名']
    ->select();

使用数组方式定义的优势是可以避免因为表名和关键字冲突而出错的情况。

3、alias

alias 用于设置当前数据表的别名,便于使用其它的连贯操作,例如 join 方法等。

示例

php 复制代码
Db::table('user')
    ->alias('u') // 为表 user 设置别名为 u
    ->join('role r ','r.user_id= u.id')
    ->select();
// 生成的SQL语句为:SELECT * FROM `user` `u` INNER JOIN `role` `r` ON `r`.`user_id`=`u`.`id`

也可以传入数组批量设置数据表以及别名,例如:

php 复制代码
Db::table('user')
    ->alias(['user' => 'u', 'role' => 'r']) // 为表 user 设置别名为 u,表 role 别名为 r
    ->join('role', 'r.user_id= u.id')
    ->select();
// 生成的SQL语句为:SELECT * FROM `user` `u` INNER JOIN `role` `r` ON `r`.`user_id`=`u`.`id`

4、field

field 方法主要作用是标识要返回或者操作的字段,可以用于查询和写入操作。

4.1、用于查询

在查询操作中,使用 field 方法指定查询字段。

php 复制代码
// 指定了查询的结果集中包含 id,name,age 三个字段的值
Db::table('user')->field('id,name,age')->select();
// 生成的SQL语句为:SELECT `id`,`name`,`age` FROM `user

也可以给某个字段设置别名,设置别名的方式与SQL语句中设置别名的方式一致。例如:

php 复制代码
// 设置 name 字段别名为 nickname
Db::table('user')->field('id,name as nickname,age')->select();
// 生成的SQL语句为:SELECT `id`,name as nickname,`age` FROM `user`

fieldRaw 方法可以直接使用函数。例如:

php 复制代码
// 使用 upper() 函数将字段的值改为大写
Db::table('user')->field('id,upper(name)')->select();
// 生成的SQL语句为:SELECT id,upper(name) FROM `user`

除了 select 方法之外,所有的查询方法,包括 find 等都可以使用 field 方法。

field 方法参数还支持传入数组。例如:

php 复制代码
Db::table('user')->field(['id', 'name', 'age'])->select();
// 生成的SQL语句为:SELECT `id`,`name`,`age` FROM `user`

最终执行的SQL和前面用字符串方式是一样的。

数组方式的定义还可以为某些字段定义别名。例如:

php 复制代码
Db::table('user')->field(['id', 'name' => 'nickname', 'age'])->select();
// 生成的SQL语句为:SELECT `id`,`name` AS `nickname`,`age` FROM `user`

如果要获取数据表中的所有字段,可以不调用 field 方法或者直接使用空的 field 方法都能做到。

php 复制代码
Db::table('user')->select();
Db::table('user')->field('*')->select(); // field 方法中传入 '*'
// 上面的用法是等效的,生成的SQL语句为:SELECT * FROM `user`

如果希望获取排除数据表中的某个或某些字段之外的所有字段值,可以使用 withoutField 方法的进行排除,该方法接受字符串或数组参数。

php 复制代码
// 获取除了 status 之外的所有字段
Db::table('user')->withoutField('status')->select();

// 要排除更多的如下所示
// 传入的参数为字符串形式:需要排除的字段以 ',' 号分隔
Db::table('user')->withoutField('status,flag')->select();
// 传入的参数为数组形式
Db::table('user')->withoutField(['status', 'flag'])->select();

注意 :字段排除功能不支持跨表和 join 操作。

4.2、用于写入

除了查询操作之外,field 方法还有一个非常重要的安全功能--字段合法性检测。field 方法结合数据库的写入方法使用就可以完成表单提交的字段合法性检测。例如:

php 复制代码
$data = ['name' => 'lisi', 'age' => 19, 'birth' => '2013'];
Db::table('user')->field('name,age')->insert($data);
// 由于合法字段只有 name 和 age,而 data 中还有 'birth' 字段,则会导致写入方法抛出异常,异常信息为:数据表字段不存在:[birth]

即表示表单中的合法字段只有 name 和 age 字段,无论用户通过什么手段更改或者添加了浏览器的提交字段,都会直接屏蔽。

在开启数据表字段严格检查的情况下,提交了非法字段会抛出异常,可以在数据库设置文件中(config\database.php)设置:

php 复制代码
// 关闭严格字段检查
'fields_strict'    =>    false,

5、strict

strict 方法用于设置是否严格检查字段名,用法如下:

php 复制代码
// 传入 false,表示该插入不严格检查字段名;true 表示严格检查字段名
Db::table('user')->field('name,age')->strict(false)->insert($data);

统默认值是由数据库配置参数 fields_strict 决定,上文已经说明了设置方法,这里不再赘述。

6、limit

limit 方法用于指定查询和操作的数量,该方法可以兼容所有的数据库驱动类。

接下来通过一些示例来说明 limit 方法的使用。

6.1、限制结果数量

在 limit(int) 方法中传入数字,可以限制查询返回数据量。例如:

php 复制代码
// 返回 5 条数据
Db::table('user')->limit(5)->select();

limit 方法也可以用于写操作。例如:

php 复制代码
// 更新 2 条满足条件的数据
Db::table('user')
    ->where('age', '>', '18')
    ->limit(2)
    ->update(['age' => 20]);

如果用于 insertAll 方法,则可以分批多次写入,每次最多写入 limit 方法指定的数量。

php 复制代码
// 分批写入数据,每次写入 100 条数据
Db::table('user')
    ->limit(100)
    ->insertAll($userList);

6.2、分页查询

limit(开始行数, 数据数量) 可以指定数据从第几行开始(第一条数据的行数为 0),返回多少条数据(和 MySQL 的 limit 语句的用法是一样的)。例如:

php 复制代码
Db::table('user')->limit(1, 2)->select();

表示查询 user 表,从第2条数据开始的2条数据。

对于大数据表,尽量使用 limit 方法限制查询结果,否则会导致很大的内存开销和性能问题。

7、page

page(页码, 每页数据量) 方法用于分页查询。

示例

php 复制代码
// 查询第一页数据
Db::table('user')->page(1, 10)->select(); 
// 查询第二页数据
Db::table('user')->page(2, 10)->select(); 

很显然,page 方法比 limit 方法在分页上更加简单,page 方法会自动计算出每个分页的 limit 参数。

8、order

order 方法用于对操作的结果排序或者优先级限制。

示例

php 复制代码
// order(排序字段, 排序方式)
Db::table('user')->order('id', 'desc')->select();

如果没有指定 desc 或者 asc 排序规则的话,默认为 asc。

也支持使用数组对多个字段的排序,例如:

php 复制代码
Db::table('user')->order(['id', 'age' => 'asc'])->select();
// 生成的SQL语句为:SELECT * FROM `user` ORDER BY `id`,`age` ASC

如果要在排序中使用mysql函数,需要使用 orderRaw 方法。

php 复制代码
Db::table('user')->orderRaw('upper(name)')->select();

9、group

group 方法通常用于结合统计函数,根据一个或多个列对结果集进行分组 。group 方法只有一个参数,支持使用字符串或数组。

示例

php 复制代码
// 查询结果按照 status 进行分组统计,统计 avg(age) 平均年龄
Db::table('user')->field('status, avg(age)')->group('status')->select();
// 生成的SQL语句为:SELECT status, avg(age) FROM `user` GROUP BY `status`

也支持对多个字段进行分组,例如:

php 复制代码
Db::table('user')->field('status, avg(age)')->group('status, flag')->select();
// 生成的SQL语句为:SELECT status, avg(age) FROM `user` GROUP BY `status`,`flag`

10、having

having 方法用于配合 group 方法完成从分组的结果中筛选(通常是聚合条件)数据。having 方法只有一个参数,并且只能使用字符串

示例

php 复制代码
Db::table('user')->field('status, avg(age)')->group('status')->having('avg(age)>19')->select();
// 生成的SQL语句为:SELECT status, avg(age) FROM `user` GROUP BY `status` HAVING avg(age)>19

11、join

join 方法用于根据两个或多个表中的列之间的关系,从这些表中查询数据。join 通常有以下几种类型,不同类型的 join 操作会影响返回的数据结果。

  • INNER JOIN:等同于 JOIN(默认的 JOIN 类型),如果表中有至少一个匹配,则返回行;
  • LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行;
  • RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行;
  • FULL JOIN:只要其中一个表中存在匹配,就返回行。

说明

php 复制代码
join ( mixed join [, mixed $condition = null [, string $type = 'INNER']] )
leftJoin ( mixed join [, mixed $condition = null ] )
rightJoin ( mixed join [, mixed $condition = null ] )
fullJoin ( mixed join [, mixed $condition = null ] )

参数

|-----------|----------------------------------------------------------------------------------------------|
| 参数 | 描述 |
| join | 要关联的(完整)表名以及别名,支持的写法: 1. [ '完整表名或者子查询'=>'别名' ] 2. '不带数据表前缀的表名'(自动作为别名) 3. '不带数据表前缀的表名 别名' |
| condition | 关联条件,只能是字符串。 |
| type | 关联类型。可以为:INNER、LEFT、RIGHT、FULL,不区分大小写,默认为INNER。 |

返回值

模型对象。

示例

php 复制代码
Db::table('user')
    ->alias('u')
    ->join('role r', 'u.role_id=r.id')
    ->select();
// 下面写法与上面的写法等效,表别名采用 [ '完整表名或者子查询'=>'别名' ] 形式
Db::table('user')
    ->alias('u')
    ->join(['role' => 'r'], 'u.role_id=r.id')
    ->select();

默认采用 INNER JOIN 方式,如果需要用其它的 JOIN 方式,只需要调用对应的方法即可。例如:使用 LEFT JOIN

php 复制代码
Db::table('user')
    ->alias('u')
    ->leftJoin(['role' => 'r'], 'u.role_id=r.id')
    ->select();

表名也可以是一个子查询,例如:

php 复制代码
$subSql = Db::table('role')->where('status', 1)->buildSql();
Db::table('user')
    ->alias('u')
    ->leftJoin([$subSql => 'r'], 'u.role_id=r.id')
    ->select();

12、union

union 操作用于合并两个或多个 SELECT 语句的结果集。

示例

php 复制代码
Db::table('user')
    ->field('name')
    ->union('select name from user')
    ->union('select name from user')
    ->select();
// 也可以在 union 方法中传入数组
// 下面的形式与上面是等效的
Db::table('user')
    ->field('name')
    ->union([
        'select name from user',
        'select name from user'
    ])
    ->select();

闭包用法:

php 复制代码
Db::table('user')
    ->field('name')
    ->union(function ($query) {
        $query->field('name')->table('user');
    })
    ->select();

支持 UNION ALL 操作,使用的是 unionAll 方法。例如:

php 复制代码
Db::table('user')
    ->field('name')
    ->unionAll('select name from user')
    ->select();

或者使用 union 方法,最后一个参数传入 true。例如:

php 复制代码
Db::table('user')
    ->field('name')
    ->union('select name from user', true)
    ->select();

每个 union 方法相当于一个独立的 SELECT 语句。

UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

13、distinct

distinct 方法用于返回唯一不同的值 。

示例

php 复制代码
Db::table('user')->field('status')->distinct(true)->select();
// 生成的SQL语句为:SELECT DISTINCT  `status` FROM `user`

distinct 方法的参数是一个布尔值。

14、lock

lock 方法用于数据库的锁机制。使用该方法后,就会自动在生成的SQL语句最后加上 FOR UPDATE 或者 FOR UPDATE NOWAIT(Oracle数据库)。

示例

php 复制代码
Db::table('user')->field('status')->lock(true)->select();
// 生成的SQL语句为:SELECT `status` FROM `user`  FOR UPDATE

15、cache

cache 方法用于查询缓存操作,也是链式操作方法之一。

cache 方法可以用于 select、find、value 和 column 方法以及其衍生方法,使用 cache 方法后,在缓存有效期之内不会再次进行数据库查询操作,而是直接获取缓存中的数据。

示例 对 find 方法使用 cache 方法

php 复制代码
Db::table('user')->where('id', 1)->cache(true)->find();

第一次查询结果会被缓存,第二次查询相同的数据的时候就会直接返回缓存中的内容,而不需要再次进行数据库查询操作。

默认情况下, 缓存有效期是由默认的缓存配置参数决定的,但 cache 方法可以单独指定。例如:

php 复制代码
Db::table('user')->where('id', 1)->cache(true, 60)->find();
// 或者使用下面的方式也是一样的
Db::table('user')->where('id', 1)->cache(60)->find();

表示对查询结果的缓存有效期为60秒。

cache 方法可以指定缓存标识:

php 复制代码
Db::table('user')->where('id', 1)->cache('key', 60)->find();

这样,在外部就可以通过 \think\facade\Cache 类直接获取查询缓存的数据。例如:

php 复制代码
$data = \think\facade\Cache::get('key');

15.1、缓存自动更新

缓存自动更新是指一旦数据更新或者删除后会自动清理缓存(下次获取的时候会自动重新缓存)。删除或者更新数据的时候,可以调用相同 key 的 cache 方法,会自动更新(清除)缓存。例如:

php 复制代码
Db::table('user')->cache('user_data')->select([1, 3, 5]);
Db::table('user')->cache('user_data')->update(['id'=>1, 'name'=>'lisi']);
Db::table('user')->cache('user_data')->select([1, 3, 5]);

最后查询的数据不会受第一条查询缓存的影响,确保查询和更新或者删除使用相同的缓存标识才能自动清除缓存。

如果使用主键进行查询和更新(或者删除)的话,无需指定缓存标识就会自动更新缓存。

php 复制代码
Db::table('user')->cache(true)->find(1);
Db::table('user')->cache(true)->where('id', 1)->update(['name'=>'lisi']);
Db::table('user')->cache(true)->find(1);

16、cacheAlways

cacheAlways 的使用方法与 cache 一样,只不过在最终表现中,如果本次查询数据为空,那么 cache 不会缓存,而 cacheAlways 会把这次空数据缓存下来,下次查询的时候会直接返回空数据。

php 复制代码
Db::table('user')->where('name', 'zhangsan')->cacheAlways('key', 60)->find();

17、fetchSql

fetchSql 方法用于直接返回SQL语句而不是执行查询,适用于任何的CURD操作方法。

示例

php 复制代码
echo Db::table('user')->fetchSql(true)->where('name', 'zhangsan')->find();
// 输出为:SELECT * FROM `user` WHERE `name` = 'zhangsan' LIMIT 1

对于某些NoSQL数据库可能不支持 fetchSql 方法。

18、failException

failException 设置查询数据为空时是否需要抛出异常,用于 select 和 find 方法。

示例

php 复制代码
// 数据不存在的话直接抛出异常
Db::name('user')
    ->where('status', 1)
    ->failException()
    ->select();

// 数据不存在返回空数组 不抛异常
Db::name('user')
    ->where('status', 1)
    ->failException(false)
    ->select();

或者可以使用更方便的查空报错:

php 复制代码
// 查询多条
Db::name('user')
    ->where('status', 1)
    ->selectOrFail();

// 查询单条
Db::name('user')
    ->where('status', 1)
    ->findOrFail();
相关推荐
bug攻城狮10 小时前
VMware 中 CentOS 7 设置静态 IP
tcp/ip·centos·php
最美不过下雨天啊12 小时前
微信小程序发送订阅消息-一次订阅,一直发送消息。
微信小程序·php·一次性订阅·长期订阅
BingoGo13 小时前
PHP serialize 序列化完全指南
后端·php
天高云淡ylz18 小时前
子网掩码的隐形陷阱:为何能ping通却无法HTTPS访问
开发语言·php
乱飞的秋天1 天前
网络编程学习
网络·学习·php
Qlittleboy1 天前
tp5的tbmember表闭包查询 openid=‘abc‘ 并且(wx_unionid=null或者wx_unionid=‘‘)
数据库·sql·php
会飞的土拨鼠呀1 天前
Linux负载如何判断服务器的压力
linux·服务器·php
悠悠~飘1 天前
php学习(第二天)
开发语言·学习·php
catchadmin1 天前
开发 PHP 扩展新途径 通过 FrankenPHP 用 Go 语言编写 PHP 扩展
android·golang·php