Thinkphp6.0 部分摘抄
Response
输出类型 | 快捷方法 | 对应Response类 |
---|---|---|
HTML输出 | response | \think\Response |
渲染模板输出 | view | \think\response\View |
JSON输出 | json | \think\response\Json |
JSONP输出 | jsonp | \think\response\Jsonp |
XML输出 | xml | \think\response\Xml |
页面重定向 | redirect | \think\response\Redirect |
附件下载 | download | \think\response\File |
返回json
<?php namespace app\controller; class Index { public function hello() { $data = ['name' => 'thinkphp', 'status' => '1']; return json($data); } }
返回html
<?php namespace app\controller; class Index { public function hello() { $data = 'Hello,ThinkPHP!'; return response($data); } }
响应参数
设置头信息
json($data)->code(201)->header([ 'Cache-control' => 'no-cache,must-revalidate' ]);
方法名 | 作用 |
---|---|
lastModified |
设置Last-Modified 头信息 |
expires |
设置Expires 头信息 |
eTag |
设置ETag 头信息 |
cacheControl |
设置Cache-control 头信息 |
contentType |
设置Content-Type 头信息 |
写入cookie
response()->cookie('name', 'value', 600);
关闭缓存
// 关闭当前页面的请求缓存 json($data)->code(201)->allowCache(false);
重定向
如果是站内重定向的话,可以支持URL组装,有两种方式组装URL,第一种是直接使用完整地址(/
打头)
redirect('/index/hello/name/thinkphp');
如果你需要自动生成URL地址,应该在调用之前调用url函数先生成最终的URL地址
redirect((string) url('hello',['name' => 'think']));
附加session闪存数据
<?php namespace app\controller; class Index { public function index() { return redirect('/hello')->with('name','thinkphp'); } public function hello() { $name = session('name'); return 'hello,'.$name.'!'; } }
重定向隐式传值使用的是Session
闪存数据隐式传值,并且仅在下一次请求有效,再次访问重定向地址的时候无效。
记住重定向之前的地址和回溯重定向
<?php namespace app\controller; class Index { public function index() { // 判断session完成标记是否存在 if (session('?complete')) { // 删除session session('complete', null); return '重定向完成,回到原点!'; } else { // 记住当前地址并重定向 return redirect('hello') ->with('name', 'thinkphp') ->remember(); } } public function hello() { $name = session('name'); return 'hello,' . $name . '! <br/><a href="/index/index/restore">点击回到来源地址</a>'; } public function restore() { // 设置session标记完成 session('complete', true); // 跳回之前的来源地址 return redirect()->restore(); } }
数据库
新版采用多类型的方式配置,方便切换数据库
type | 数据库 |
---|---|
mysql | MySQL |
sqlite | SqLite |
pgsql | PostgreSQL |
sqlsrv | SqlServer |
mongo | MongoDb |
oracle | Oracle |
内置参数
PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, PDO::ATTR_STRINGIFY_FETCHES => false, PDO::ATTR_EMULATE_PREPARES => false,
在数据库配置文件中设置的params
参数中的连接配置将会和内置的设置参数合并,如果需要使用长连接,并且返回数据库的小写列名,可以在数据库配置文件中增加下面的定义:
'params' => [ \PDO::ATTR_PERSISTENT => true, \PDO::ATTR_CASE => \PDO::CASE_LOWER, ],
多个连接
return [ 'default' => 'mysql', 'connections' => [ 'mysql' => [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '127.0.0.1', // 数据库名 'database' => 'thinkphp', // 数据库用户名 'username' => 'root', // 数据库密码 'password' => '', // 数据库连接端口 'hostport' => '', // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => 'think_', ], 'demo' => [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '127.0.0.1', // 数据库名 'database' => 'demo', // 数据库用户名 'username' => 'root', // 数据库密码 'password' => '', // 数据库连接端口 'hostport' => '', // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => 'think_', ], ], ];
动态选择数据库连接
\think\facade\Db::connect('demo') ->table('user') ->find();
配置参考参数
参数名 | 描述 | 默认值 |
---|---|---|
type | 数据库类型 | 无 |
hostname | 数据库地址 | 127.0.0.1 |
database | 数据库名称 | 无 |
username | 数据库用户名 | 无 |
password | 数据库密码 | 无 |
hostport | 数据库端口号 | 无 |
dsn | 数据库连接dsn信息 | 无 |
params | 数据库连接参数 | 空 |
charset | 数据库编码 | utf8 |
prefix | 数据库的表前缀 | 无 |
deploy | 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) | 0 |
rw_separate | 数据库读写是否分离 主从式有效 | false |
master_num | 读写分离后 主服务器数量 | 1 |
slave_no | 指定从服务器序号 | 无 |
fields_strict | 是否严格检查字段是否存在 | true |
fields_cache | 是否开启字段缓存 | false |
schema_cache_path | 字段缓存目录 | 无 |
trigger_sql | 是否开启SQL监听 | true |
auto_timestamp | 自动写入时间戳字段 | false |
query | 指定查询对象 | think\db\Query |
短线重连
// 开启断线重连 'break_reconnect' => true,
分布式数据库
多个数据库配置
return [ 'default' => 'mysql', 'connections' => [ 'mysql' => [ // 启用分布式数据库 'deploy' => 1, // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' =>[ '192.168.1.1','192.168.1.2','192.168.1.3'], // 数据库名 'database' => 'demo', // 数据库用户名 'username' => 'root,slave,slave', // 数据库密码 'password' => ['123456','abc,def','hello'] // 数据库连接端口 'hostport' => '', // 数据库字符集 'charset' => 'utf8', ], ], ];
设置读写分离
'rw_separate' => true,
发生下列情况,会主动连接主服务器
- 使用了数据库的写操作方法(
execute
/insert
/update
/delete
以及衍生方法); - 如果调用了数据库事务方法的话,会自动连接主服务器;
- 从服务器连接失败,会自动连接主服务器;
- 调用了查询构造器的
lock
方法; - 调用了查询构造器的
master
/readMaster
方法
主从数据库的数据同步工作不在框架实现,需要数据库考虑自身的同步或者复制机制。
如果在大数据量或者特殊的情况下写入数据后可能会存在同步延迟的情况,可以调用master()
方法进行主库查询操作。
代码调用主库
Db::name('user') ->where('id', 1) ->update(['name' => 'thinkphp']); Db::name('user') ->master(true) ->find(1);
开启自动主库读取
// 开启自动主库读取 'read_master' => true,
开启后,一旦我们对某个数据表进行了写操作,那么当前请求的后续所有对该表的查询都会使用主库读取。
查询构造器
Db::table('think_user')->where('status', 1)->select()->toArray(); // 查不到以后抛出异常 Db::table('think_user')->where('status',1)->selectOrFail(); // 如果设置表前缀,使用name,而不是table Db::name('user')->where('id', 1)->find(); Db::name('user')->where('status', 1)->select(); // 返回某个字段的值 Db::table('think_user')->where('id', 1)->value('name');
数据分批处理
Db::table('think_user')->chunk(100, function($users) { foreach ($users as $user) { // } });
在闭包中返回false终止循环
Db::table('think_user')->chunk(100, function($users) { foreach ($users as $user) { // 处理结果集... if($user->status==0){ return false; } } });
游标查询
该查询方式利用了PHP的生成器特性,可以大幅减少大量数据查询的内存开销问题。
$cursor = Db::table('user')->where('status', 1)->cursor(); foreach($cursor as $user){ echo $user['name']; }
添加数据
$data = ['foo' => 'bar', 'bar' => 'foo']; Db::name('user')->insert($data); Db::name('user')->save($data);
mysql支持replace和返回自增id
Db::name('user')->replace()->insert($data); $userId = Db::name('user')->insertGetId($data);
分批插入多条数据
$data = [ ['foo' => 'bar', 'bar' => 'foo'], ['foo' => 'bar1', 'bar' => 'foo1'], ['foo' => 'bar2', 'bar' => 'foo2'] ... ]; // 分批写入 每次最多100条数据 Db::name('user') ->limit(100) ->insertAll($data);
更新数据
Db::name('user') ->where('id', 1) ->update(['name' => 'thinkphp']); Db::name('user') ->save(['id' => 1, 'name' => 'thinkphp']);
data方法传入要更新的数据
Db::name('user') ->where('id', 1) ->data(['name' => 'thinkphp']) ->update()
自增/自减
// score 字段加 5 Db::table('think_user') ->where('id', 1) ->inc('score', 5) ->update(); // score 字段减 1 Db::table('think_user') ->where('id', 1) ->dec('score') ->update();
删除数据
// 根据主键删除 Db::table('think_user')->delete(1); Db::table('think_user')->delete([1,2,3]); // 条件删除 Db::table('think_user')->where('id',1)->delete(); Db::table('think_user')->where('id','<',10)->delete();
无条件删除:delete from table
// 无条件删除所有数据 Db::name('user')->delete(true);
软删除
// 软删除数据 使用delete_time字段标记删除 Db::name('user') ->where('id', 1) ->useSoftDelete('delete_time',time()) ->delete();
查询表达式
表达式 | 含义 | 快捷查询方法 |
---|---|---|
= | 等于 | |
<> | 不等于 | |
> | 大于 | |
>= | 大于等于 | |
< | 小于 | |
<= | 小于等于 | |
[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 |
<= TIME | 小于等于某个时间 | whereTime |
EXP | 表达式查询,支持SQL语法 | whereExp |
find in set | FIND_IN_SET查询 | whereFindInSet |
链式调用
table
Db::field('user.name,role.title') ->table([ 'think_user'=>'user', 'think_role'=>'role' ]) ->limit(10)->select();
field
Db::table('user')->field('id,nickname as name')->select();
Db::table('user')->fieldRaw('id,SUM(score)')->select();
字段排除
Db::table('user')->withoutField('user_id,content')->select(); //或者用 Db::table('user')->withoutField(['user_id','content'])->select();
page
// 查询第一页数据 Db::table('article')->page(1,10)->select(); // 查询第二页数据 Db::table('article')->page(2,10)->select(); // page和limit一起使用 Db::table('article')->limit(25)->page(3)->select();
order
Db::table('user') ->where('status', 1) ->order(['order','id'=>'desc']) ->limit(5) ->select();
cache
cache可以用于select
、find
、value
和column
方法,以及其衍生方法,使用cache
方法后,在缓存有效期之内不会再次进行数据库查询操作,而是直接获取缓存中的数据
Db::table('user')->where('id',5)->cache(true)->find();
缓存默认有效期是由默认的缓存配置参数决定的
Db::table('user')->cache(true,60)->find(); // 或者使用下面的方式 是等效的 Db::table('user')->cache(60)->find();
一旦数据更新或者删除后会自动清理缓存(下次获取的时候会自动重新缓存)
fetchSql
echo Db::table('user')->fetchSql(true)->find(1);
强制索引查询
Db::table('user')->force('user')->select();
partition
// 用于查询 Db::name('log') ->partition(['p1','p2']) ->select(); // 用于写入 Db::name('user') ->partition('p1') ->insert(['name' => 'think', 'score' => 100']);
sequence
方法用于pgsql
数据库指定自增序列名
Db::name('user') ->sequence('user_id_seq') ->insert(['name'=>'thinkphp']);
extra,mysql中的DELAYED,IGNORE,ON DUPLICATE KEY UPDATE
Db::name('user') ->extra('IGNORE') ->insert(['name' => 'think']); Db::name('user') ->extra('DELAYED') ->insert(['name' => 'think']); Db::name('user') ->extra('SQL_BUFFER_RESULT') ->select();
DUPLICATE
Db::name('user') ->duplicate(['score' => 10]) ->insert(['name' => 'think']);
procedure,是否是存储过程
$resultSet = Db::procedure(true) ->query('call procedure_name');
聚合查询
方法 | 说明 |
---|---|
count | 统计数量,参数是要统计的字段名(可选) |
max | 获取最大值,参数是要统计的字段名(必须) |
min | 获取最小值,参数是要统计的字段名(必须) |
avg | 获取平均值,参数是要统计的字段名(必须) |
sum | 获取总分,参数是要统计的字段名(必须) |
分页查询
// 查询状态为1的用户数据 并且每页显示10条数据 $list = Db::name('user')->where('status',1)->order('id', 'desc')->paginate(10); // 渲染模板输出 return view('index', ['list' => $list]);
模板文件
<div> <ul> {volist name='list' id='user'} <li> {$user.nickname}</li> {/volist} </ul> </div> {$list|raw}
获取单独页总的数量
// 查询状态为1的用户数据 并且每页显示10条数据 $list = Db::name('user')->where('status',1)->order('id' ,'desc')->paginate(10); // 获取总记录数 $count = $list->total(); return view('index', ['list' => $list, 'count' => $count]);
传入总结数,不会自动进行总数计算
// 查询状态为1的用户数据 并且每页显示10条数据 总记录数为1000 $list = Db::name('user')->where('status',1)->paginate(10,1000); // 获取分页显示 $page = $list->render(); return view('index', ['list' => $list, 'page' => $page]);
分页后数据处理
$list = Db::name('user')->where('status',1)->order('id', 'desc')->paginate()->each(function($item, $key){ $item['nickname'] = 'think'; return $item; });
模型数据操作,闭包中不需要返回值
$list = User::where('status',1)->order('id', 'desc')->paginate()->each(function($item, $key){ $item->nickname = 'think'; });
时间比较
官方文档:https://www.kancloud.cn/manual/thinkphp6_0/1037565
高级查询
快捷查询
Db::table('think_user') ->where('name|title','like','thinkphp%') ->where('create_time&update_time','>',0) ->find();
批量查询
Db::table('think_user') ->where([ ['name', 'like', 'thinkphp%'], ['title', 'like', '%thinkphp'], ['id', '>', 0], ['status', '=', 1], ]) ->select();
如果使用exp,一定要使用raw
Db::table('think_user') ->where([ ['name', 'like', 'thinkphp%'], ['title', 'like', '%thinkphp'], ['id', 'exp', Db::raw('>score')], ['status', '=', 1], ]) ->select();
$map = [ ['name', 'like', 'thinkphp%'], ['title', 'like', '%thinkphp'], ['id', '>', 0], ]; Db::table('think_user') ->where([ $map ]) ->where('status',1) ->select();
闭包查询
$name = 'thinkphp'; $id = 10; Db::table('think_user')->where(function ($query) use($name, $id) { $query->where('name', $name) ->whereOr('id', '>', $id); })->select();
混合查询
Db::table('think_user') ->where('name', 'like', 'thinkphp%') ->where(function ($query) { $query->where('id', '<', 10); }) ->select();
字符串条件查询
Db::table('think_user') ->whereRaw('id > 0 AND name LIKE "thinkphp%"') ->select();
参数绑定
Db::table('think_user') ->whereRaw('id > :id AND name LIKE :name ', ['id' => 0, 'name' => 'thinkphp%']) ->select();
快捷方法
方法 | 作用 |
---|---|
whereOr |
字段OR查询 |
whereXor |
字段XOR查询 |
whereNull |
查询字段是否为Null |
whereNotNull |
查询字段是否不为Null |
whereIn |
字段IN查询 |
whereNotIn |
字段NOT IN查询 |
whereBetween |
字段BETWEEN查询 |
whereNotBetween |
字段NOT BETWEEN查询 |
whereLike |
字段LIKE查询 |
whereNotLike |
字段NOT LIKE查询 |
whereExists |
EXISTS条件查询 |
whereNotExists |
NOT EXISTS条件查询 |
whereExp |
表达式查询 |
whereColumn |
比较两个字段 |
动态查询
动态查询 | 描述 |
---|---|
whereFieldName |
查询某个字段的值 |
whereOrFieldName |
查询某个字段的值 |
getByFieldName |
根据某个字段查询 |
getFieldByFieldName |
根据某个字段获取某个值 |
// 根据邮箱(email)查询用户信息 $user = Db::table('user') ->whereEmail('thinkphp@qq.com') ->find(); // 根据昵称(nick_name)查询用户 $email = Db::table('user') ->whereNickName('like', '%流年%') ->select(); // 根据邮箱查询用户信息 $user = Db::table('user') ->getByEmail('thinkphp@qq.com'); // 根据昵称(nick_name)查询用户信息 $user = Db::table('user') ->field('id,name,nick_name,email') ->getByNickName('流年'); // 根据邮箱查询用户的昵称 $nickname = Db::table('user') ->getFieldByEmail('thinkphp@qq.com', 'nick_name'); // 根据昵称(nick_name)查询用户邮箱 $email = Db::table('user') ->getFieldByNickName('流年', 'email');
条件查询
Db::name('user')->when($condition, function ($query) { // 满足条件后执行 $query->where('score', '>', 80)->limit(10); })->select();
满足条件的查询,不满足条件的查询
Db::name('user')->when($condition, function ($query) { // 满足条件后执行 $query->where('score', '>', 80)->limit(10); }, function ($query) { // 不满足条件执行 $query->where('score', '>', 60); });
视图查询
视图查询可以实现不依赖数据库视图的多表查询,并不需要数据库支持视图,是JOIN方法的推荐替代方法
Db::view('User', 'id,name') ->view('Profile', 'truename,phone,email', 'Profile.user_id=User.id') ->view('Score', 'score', 'Score.user_id=Profile.id') ->where('score', '>', 80) ->select();
默认是inner join,如果用left join
Db::view('User', 'id,name') ->view('Profile', 'truename,phone,email', 'Profile.user_id=User.id', 'LEFT') ->view('Score', 'score', 'Score.user_id=Profile.id', 'RIGHT') ->where('score', '>', 80) ->select();
Db::view(['think_user' => 'member'], ['id' => 'uid', 'name' => 'account']) ->view('Profile', 'truename,phone,email', 'Profile.user_id=member.id') ->view('Score', 'score', 'Score.user_id=Profile.id') ->where('score', '>', 80) ->select();
JSON字段
json插入
$user['name'] = 'thinkphp'; $user['info'] = [ 'email' => 'thinkphp@qq.com', 'nickname' => '流年', ]; Db::name('user') ->json(['info']) ->insert($user);
JSON数据查询
$user = Db::name('user') ->json(['info']) ->find(1); dump($user);
JSON字段属性不会自动获取,可以手动设置类型
$user = Db::name('user') ->json(['info']) ->where('info->user_id', 10) ->setFieldType(['info->user_id' => 'int']) ->find(); dump($user);
json更新
$data['info'] = [ 'email' => 'kancloud@qq.com', 'nickname' => 'kancloud', ]; Db::name('user') ->json(['info']) ->where('id',1) ->update($data);
子查询
使用buildSql构造子查询
$subQuery = Db::table('think_user') ->field('id,name') ->where('id', '>', 10) ->buildSql();
使用子查询
Db::table($subQuery . ' a') ->where('a.name', 'like', 'thinkphp') ->order('id', 'desc') ->select();
闭包构造子查询
Db::table('think_user') ->where('id', 'IN', function ($query) { $query->table('think_profile')->where('status', 1)->field('id'); }) ->select();
原生查询
query
方法用于执行SQL
查询操作,返回查询结果数据集(数组)
Db::query("select * from think_user where status=:id", ['id' => 1]);
execute
用于更新和写入数据的sql操作,如果数据非法或者查询错误则返回false
,否则返回影响的记录数
// 参数绑定 Db::query("select * from think_user where id=? AND status=?", [8, 1]); // 命名绑定 Db::execute("update think_user set name=:name where status=:status", ['name' => 'thinkphp', 'status' => 1]);
查询事件
事件 | 描述 |
---|---|
before_select | select 查询前回调 |
before_find | find 查询前回调 |
after_insert | insert 操作成功后回调 |
after_update | update 操作成功后回调 |
after_delete | delete 操作成功后回调 |
\think\facade\Db::event('before_select', function ($query) { // 事件处理 return $result; });
获取器
Db::name('user')->withAttr('name', function($value, $data) { return strtolower($value); })->select();
$user = Db::name('user') ->json(['info']) ->withAttr('info.name', function($value, $data) { return strtolower($value); })->find(1); dump($user);
事务操作
闭包事务
Db::transaction(function () { Db::table('think_user')->find(1); Db::table('think_user')->delete(1); });
手动控制
// 启动事务 Db::startTrans(); try { Db::table('think_user')->find(1); Db::table('think_user')->delete(1); // 提交事务 Db::commit(); } catch (\Exception $e) { // 回滚事务 Db::rollback(); }
XA事务实现分布式事务
Db::transactionXa(function () { Db::connect('db1')->table('think_user')->delete(1); Db::connect('db2')->table('think_user')->delete(1); }, [Db::connect('db1'),Db::connect('db2')]);
存储过程
$resultSet = Db::query('call procedure_name'); foreach ($resultSet as $result) { }
$resultSet = Db::query('call procedure_name(:in_param1,:in_param2,:out_param)', [ 'in_param1' => $param1, 'in_param2' => [$param2, PDO::PARAM_INT], 'out_param' => [$outParam, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 4000], ]);
获取数据集
返回的数据集对象是think\Collection,提供了和数组无差别用法,并且另外封装了一些额外的方法。
// 获取数据集 $users = Db::name('user')->select(); // 遍历数据集 foreach($users as $user){ echo $user['name']; echo $user['id']; }
通过isEmpty判断是否为空
$users = Db::name('user')->select(); if($users->isEmpty()){ echo '数据集为空'; }
自定义数据库驱动
如果你需要自定义数据库驱动,需要自定义实现Connection
类(或者继承think\db\Connection
)和Builder
类(或者继承think\db\Builder
)
对于特殊的驱动,可能还需要实现Query
类(或者继承think\db\Query)
'type' => 'think\mongo\Connection', 'query' => 'think\mongo\Query',
睁开眼,书在面前 闭上眼,书在心里