ThinkPHP6 数据库链式操作
数据库提供的链式操作方法,可以有效的提高数据存取的代码清晰度和开发效率,并且支持所有的
CURD
操作带*标识的表示支持多次调用
连贯操作 | 作用 | 支持的参数类型 |
---|---|---|
where* | 用于AND查询 | 字符串、数组和对象 |
table | 用于定义要操作的数据表名称 | 字符串和数组 |
name | 用于定义要操作的数据表名称 | 字符串 |
field* | 用于定义要查询的字段(支持字段排除) | 字符串和数组 |
order* | 用于对结果排序 | 字符串和数组 |
limit | 用于限制查询结果数量 | 字符串和数字 |
page | 用于查询分页(内部会转换成limit) | 字符串和数字 |
一、表达式查询
表达式是SQL语句的条件
表达式不分大小写
表达式写在where里
表达式 | 含义 |
---|---|
= | 等于 |
<> | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
[NOT] LIKE | 模糊查询 |
[NOT] BETWEEN | (不在)区间查询 |
[NOT] IN | (不在)IN 查询 |
[NOT] NULL | 查询字段是否(不)是NULL |
where
查询
where方法在链式操作方法里面是最常用的方法,可以完成包括普通查询、表达式查询、快捷查询、区间查询、组合查询在内的条件查询操作
# 等于(=)$select = Db::table('shop_goods')->where('id','=','6')->select();print_r($select->toArray());# 不等于(<>)$select = Db::table('shop_goods')->where('id','<>','2')->select();print_r($select->toArray());# 大于(>)$select = Db::table('shop_goods')->where('id','>','3')->select();print_r($select->toArray());# 大于等于(>=)$select = Db::table('shop_goods')->where('id','>=','5')->select();print_r($select->toArray());# 小于(<)$select = Db::table('shop_goods')->where('id','<','5')->select();print_r($select->toArray());# 小于等于(<=)$select = Db::table('shop_goods')->where('id','<=','5')->select();print_r($select->toArray());# 多where 大于3且小于8 (4 5 6 7)$select = Db::table('shop_goods') ->where('id','>','3') ->where('id','<','8') ->select();print_r($select->toArray());# LIKE *匹配一个字符 %匹配多个字符 匹配标题含有连衣裙三个字的商品$select = Db::table('shop_goods')->where('title','like','%连衣裙%')->select();print_r($select->toArray());# NOT LIKE 匹配标题中没有连衣裙三个字的商品$select = Db::table('shop_goods')->where('title','not like','%连衣裙%')->select();print_r($select->toArray());# BETWEEN 在6到10之间的$select = Db::table('shop_goods')->where('id','between','6,10')->select();print_r($select->toArray());# NOT BETWEEN 除了6到10以外的$select = Db::table('shop_goods')->where('id','not between',[6,10])->select();print_r($select->toArray());# IN 包含$select = Db::table('shop_goods')->where('id','in','4,7,10')->select();print_r($select->toArray());# NOT IN 不包含$select = Db::table('shop_goods')->where('id','not in',[4,7,10])->select();print_r($select->toArray());
二、数据表
1、table 和 name
# 必须完整数据库名$select = Db::table('shop_goods')->where('id','10')->select();print_r($select->toArray());# 数据库未设置前缀$select = Db::name('shop_goods')->where('id','11')->select();print_r($select->toArray());# 数据库设置前缀,无前缀访问$select = Db::name('goods')->where('id','12')->select();print_r($select->toArray());
2、数据库前缀
数据库配置 database.php
return [ 'connections' => [ 'mysql' => [ // 数据库表前缀 'prefix' => Env::get('database.prefix', 'shop_'), ] ]];
三、返回值
1、field
field 方法主要作用是标识要返回或者操作的字段,可以用于查询和写入操作
所有的查询方法都可以使用field方法
# 字符串$select = Db::table('shop_goods') ->field('title,price,discount as d') ->where('status',1) ->select();print_r($select->toArray());# 数组$select = Db::table('shop_goods') ->field([ 'title', 'price', 'discount'=>'d' ]) ->where('status',1) ->select();print_r($select->toArray());# 添加,只能添加这几个字段# 多field$data = [ 'title' => '新商品', 'price' => 50, 'dicount' => 8, 'add_time' => 1576080000];$insert = Db::table('shop_goods') ->field('title') ->field('price') ->field('discount') ->field('add_time') ->insert($data);print_r($insert);# 查询全部字段,速度较快$select = Db::table('shop_goods') ->field(true) // ->field('*') ->where('status',1) ->select();print_r($select->toArray());
2、withoutField
withoutField 方法作用 排除数据表中的字段
Db::table('shop_goods')->withoutField('id')->select();
3、fieldRaw
fieldRaw 方法直接使用mysql函数
Db::table('shop_goods')->fieldRaw('id,sum(price)')->select();
四、排序
1、order
方法用于对操作的结果排序或者优先级限制
默认正序
asc 正序
desc 倒序
$select = Db::table('shop_goods') ->field('title,price,id') ->where('status',1) ->order('price','DESC') ->order('id','DESC') ->select();print_r($select->toArray());
2、orderRaw
方法中使用mysql函数
$select = Db::table('shop_goods') ->field('title,price,id') ->where('status',1) ->orderRaw("field(title,'price','discount','stock')") ->select();print_r($select->toArray());
五、分页
limit
方法主要用于指定查询和操作的数量
$select = Db::table('shop_goods') ->field('title,price,id') ->where('status',1) ->order('price','DESC') ->limit(3) ->select();print_r($select->toArray());$select = Db::table('shop_goods') ->field('title,price,id') ->where('status',1) ->order('price','DESC') ->limit(6,5) ->select();print_r($select->toArray());
page
方法主要用于分页查询
$select = Db::table('shop_goods') ->field('title,price,id') ->where('status',1) ->order('price','DESC') ->page(2,5) ->select();print_r($select->toArray());
六、聚合查询
聚合方法如果没有数据,默认都是0,聚合查询都可以配合其它查询条件
方法 | 功能 |
---|---|
count | 统计数量,参数是要统计的字段名(可选) |
max | 获取最大值,参数是要统计的字段名(必须) |
min | 获取最小值,参数是要统计的字段名(必须) |
avg | 获取平均值,参数是要统计的字段名(必须) |
sum | 获取总数,参数是要统计的字段名(必须) |
// 统计数量,参数是要统计的字段名(可选)$select = Db::table('shop_goods')->count();print_r($select);// 获取最大值,参数是要统计的字段名(必须)$select = Db::table('shop_goods')->max('id');print_r($select);// 获取最小值,参数是要统计的字段名(必须)$select = Db::table('shop_goods')->min('id');print_r($select);// 获取平均值,参数是要统计的字段名(必须)$select = Db::table('shop_goods')->avg('id');print_r($select);// 获取总数,参数是要统计的字段名(必须)$select = Db::table('shop_goods')->sum('id');print_r($select);
七、搜索、排序示例
controller代码
public function index(){ $title = '商城'; $login = '欧阳克'; # 左侧菜单 $menu = Db::table('shop_menu')->where('fid',0)->select(); $left = $menu->toArray(); foreach($left as &$left_v){ $left_v['lists'] = Db::table('shop_menu')->where('fid',$left_v['id'])->select(); } # 右侧列表 $param = Request::param(); if(isset($param['status']) && $param['status'] == 1){ $where['status'] = 1; }else if(isset($param['status']) && $param['status'] == 2){ $where['status'] = 2; }else{ $where = true; } $list = Db::table('shop_goods') ->where($where) ->order('add_time DESC') ->order('id DESC') ->select(); $right = $list->toArray(); foreach($right as &$right_v){ $right_v['cat'] = Db::table('shop_cat')->where('id',$right_v['cat'])->value('name'); } View::assign([ 'title' => $title, 'login' => $login, 'left' => $left, 'right' => $right, 'status' => isset($param['status']) ? $param['status'] : 0 ]); return View::fetch();}
view代码
<form class="layui-form" method="post"> <div class="layui-form-item" style="margin-top:10px;"> <div class="layui-input-inline"> <select name="status"> <option value="0" {if $status==0}selected{/if}>全部</option> <option value="1" {if $status==1}selected{/if}>开启</option> <option value="2" {if $status==2}selected{/if}>关闭</option> </select> </div> <button class="layui-btn layui-btn-primary"><i class="layui-icon"></i>搜索</button> </div></form>
八、分页示例
controller代码
public function index(){ $title = '商城'; $login = '欧阳克'; # 左侧菜单 $menu = Db::table('shop_menu')->where('fid',0)->select(); $left = $menu->toArray(); foreach($left as &$left_v){ $left_v['lists'] = Db::table('shop_menu')->where('fid',$left_v['id'])->select(); } # 右侧列表 $param = Request::param(); if(isset($param['status']) && $param['status'] == 1){ $where['status'] = 1; }else if(isset($param['status']) && $param['status'] == 2){ $where['status'] = 2; }else{ $where = true; } // 获取当前页数 $page = isset($param['page']) ? $param['page'] : 1; // 统计总条数 $count = Db::table('shop_goods')->where($where)->count(); // 每页条数 $num = 6; $list = Db::table('shop_goods') ->where($where) ->order('add_time DESC') ->order('id DESC') ->page($page,$num) ->select(); $right = $list->toArray(); foreach($right as &$right_v){ $right_v['cat'] = Db::table('shop_cat')->where('id',$right_v['cat'])->value('name'); } View::assign([ 'title' => $title, 'login' => $login, 'left' => $left, 'right' => $right, 'count' => ceil($count/$num), 'page' => $page, 'status' => isset($param['status']) ? $param['status'] : 0 ]); return View::fetch();}
view代码
<div class="layui-box layui-laypage layui-laypage-default"> <a href="{if $page<=1}javascript:;{else/}?page={$page-1}&status={$status}{/if}" class="layui-laypage-prev {if $page<=1}layui-disabled{/if}">上一页</a> {for start="0" end="$count"} {if $page == $i+1} <span class="layui-laypage-curr"> <em class="layui-laypage-em"></em> <em>{$i+1}</em> </span> {else/} <a href="?page={$i+1}&status={$status}">{$i+1}</a> {/if} {/for} <a href="{if $page>=$count}javascript:;{else/}?page={$page+1}&status={$status}{/if}" class="layui-laypage-next {if $page>=$count}layui-disabled{/if}">下一页</a></div>
九、模版分页
paginate
内置了分页实现,要给数据添加分页输出功能变得非常简单render
获取翻页html代码total
获取总数量
controller代码
$select = Db::table('shop_goods')->paginate(10);print_r($select);echo '<hr>';foreach($select as $v){ print_r($v);echo '<hr>';}// 生成分页的html代码可以传给视图print_r($select->render());echo '<hr>';print_r('总数:'.$select->total());echo '<hr>';View::assign([ 'paginate' => $select, 'render'=> $select->render(), 'list' => $select->data()]);return View::fetch();
view代码
<!-- 视图中生成分页html代码 --><div>{$paginate|raw}</div><!-- 控制器传递过来的分页html代码 --><div>{$render}</div>
css代码 内置分页采用的是bootstrap分页组件,我们需要引入分页条样式
.pagination { display: inline-block; padding-left: 0; margin: 20px 0; border-radius: 4px;}.pagination > li { display: inline;}.pagination > li > a,.pagination > li > span { position: relative; float: left; padding: 6px 12px; margin-left: -1px; line-height: 1.42857143; color: #337ab7; text-decoration: none; background-color: #fff; border: 1px solid #ddd;}.pagination > li:first-child > a,.pagination > li:first-child > span { margin-left: 0; border-top-left-radius: 4px; border-bottom-left-radius: 4px;}.pagination > li:last-child > a,.pagination > li:last-child > span { border-top-right-radius: 4px; border-bottom-right-radius: 4px;}.pagination > li > a:hover,.pagination > li > span:hover,.pagination > li > a:focus,.pagination > li > span:focus { z-index: 2; color: #23527c; background-color: #eee; border-color: #ddd;}.pagination > .active > a,.pagination > .active > span,.pagination > .active > a:hover,.pagination > .active > span:hover,.pagination > .active > a:focus,.pagination > .active > span:focus { z-index: 3; color: #fff; cursor: default; background-color: #337ab7; border-color: #337ab7;}.pagination > .disabled > span,.pagination > .disabled > span:hover,.pagination > .disabled > span:focus,.pagination > .disabled > a,.pagination > .disabled > a:hover,.pagination > .disabled > a:focus { color: #777; cursor: not-allowed; background-color: #fff; border-color: #ddd;}
十、模版分页示例
参数 | 描述 |
---|---|
list_rows | 每页数量 |
page | 当前页 |
path | url路径 |
query | url额外参数 |
fragment | url锚点 |
var_page | 分页变量 |
controller代码
public function index(){ $title = '商城'; $login = '欧阳克'; # 左侧菜单 $menu = Db::table('shop_menu')->where('fid',0)->select(); $left = $menu->toArray(); foreach($left as &$left_v){ $left_v['lists'] = Db::table('shop_menu')->where('fid',$left_v['id'])->select(); } # 右侧列表 $param = Request::param(); if(isset($param['status']) && $param['status'] == 1){ $where['status'] = 1; }else if(isset($param['status']) && $param['status'] == 2){ $where['status'] = 2; }else{ $where = true; } $page = isset($param['page']) ? $param['page'] : 1; # thinkphp 自带分页 $list = Db::table('shop_goods') ->where($where) ->order('add_time DESC') ->order('id DESC') ->paginate([ 'list_rows'=> 6, 'query' => Request::param() ]); $right = $list->toArray(); foreach($right['data'] as &$right_v){ $right_v['cat'] = Db::table('shop_cat')->where('id',$right_v['cat'])->value('name'); } View::assign([ 'title' => $title, 'login' => $login, 'left' => $left, // 查询出的数据用于渲染商品列表 'right' => $right['data'], // 注意:paginate查询出的对象中data才是我们的数据 'paginate' => $list, // 这里需要将data中数据抽离给前端渲染列表,是因为我们将结果对象转换为了数组,默认是不需要这样的,直接将paginate查询结果传递过去即可,和之前的select一样操作 'status' => isset($param['status']) ? $param['status'] : 0 ]); return View::fetch();}
view代码
// $paginate中数据为paginate()查询出的,|raw<div>{$paginate|raw}</div>
十一、SQL 调试
getLastSql
输出上次执行的sql语句getLastSql
方法只能获取最后执行的 SQL 记录
$select = Db::table('shop_goods')->select();// 查询结果对象print_r($select);echo Db::getLastSql();// SELECT * FROM `shop_goods` 为上一次执行的SQL语句
fetchSql
方法直接返回当前的 SQL 而不执行
$select = Db::table('shop_goods')->field('*')->order('id desc')->fetchSql()->select();echo $select;// SELECT * FROM `shop_goods` ORDER BY `id` DESC 查询语句不会被执行,而是直接输出
十二、动态配置数据库
config目录database.php文件
use think\facade\Env;return [ 'connections' => [ 'zhang' => [ // 数据库类型 'type' => Env::get('database.type', 'mysql'), // 服务器地址 'hostname' => Env::get('database.hostname', '127.0.0.1'), // 数据库名 'database' => 'mydb', // 用户名 'username' => Env::get('database.username', 'root'), // 密码 'password' => Env::get('database.password', 'root'), // 端口 'hostport' => Env::get('database.hostport', '3306'), // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => Env::get('database.charset', 'utf8'), // 数据库表前缀 'prefix' => Env::get('database.prefix', 'shop_'), // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, // 数据库读写是否分离 主从式有效 'rw_separate' => false, // 读写分离后 主服务器数量 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', // 是否严格检查字段是否存在 'fields_strict' => true, // 是否需要断线重连 'break_reconnect' => false, // 监听SQL 'trigger_sql' => true, // 开启字段缓存 'fields_cache' => false, // 字段缓存路径 'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, ] ]];
mydb数据库中的shop_user表
CREATE TABLE `shop_user` ( `uid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', `account` varchar(50) NOT NULL COMMENT '账户', `password` char(32) NOT NULL COMMENT '密码', `name` varchar(50) NOT NULL COMMENT '姓名', `status` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态 1开启 2关闭', `add_time` int(10) unsigned NOT NULL COMMENT '添加时间', PRIMARY KEY (`uid`)) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='后台管理员';
connect
方法动态配置数据库连接信息
Db::connect('zhang')->table('shop_user')->select();
connect
方法必须在查询的最开始调用,而且必须紧跟着调用查询方法,否则可能会导致部分查询失效或者依然使用默认的数据库连接
十三、WHRER 链式操作(不常用)
和查询表达式功能一样,ThinkPHP 提供以下快捷查询方法
连贯操作 | 作用 | 支持的参数类型 |
---|---|---|
whereOr* | 用于OR查询 | 字符串、数组和对象 |
whereLike* | 模糊查询 | 字符串 |
whereNotLike* | 模糊查询 | 字符串 |
whereBetween* | 区间查询 | 字符串 |
whereNotBetween* | 不在区间查询 | 字符串 |
whereIn* | IN查询 | 字符串 |
whereNotIn* | 不在IN查询 | 字符串 |
whereNull* | 查询字段是否是NULL | 字符串 |
whereNotNull* | 查询字段是否不是NULL | 字符串 |
whereExists* | EXISTS查询 | 字符串 |
whereNotExists* | 不在EXISTS查询 | 字符串 |
whereBetweenTime* | 时间区间比较 | 字符串 |
whereTime* | 用于时间日期的快捷查询 | 字符串 |
whereExp* | 表达式查询,支持SQL语法 | 字符串 |
whereFindInSet* | FIND_IN_SET查询 | 字符串 |
whereRaw* | 用于字符串条件直接查询和操作 | 字符串 |
十四、其他链式操作(不常用)
连贯操作 | 作用 | 支持的参数类型 |
---|---|---|
alias | 用于给当前数据表定义别名 | 字符串 |
strict | 用于设置是否严格检测字段名是否存在 | 布尔值 |
group | 用于对查询的group支持 | 字符串 |
having | 用于对查询的having支持 | 字符串 |
join* | 用于对查询的join支持 | 字符串和数组 |
union* | 用于对查询的union支持 | 字符串、数组和对象 |
distinct | 用于查询的distinct支持 | 布尔值 |
lock | 用于数据库的锁机制 | 布尔值 |
cache | 用于查询缓存 | 支持多个参数 |
comment | 用于SQL注释 | 字符串 |
force | 用于数据集的强制索引 | 字符串 |
partition | 用于设置分区信息 | 数组 字符串 |
failException | 用于设置没有查询到数据是否抛出异常 | 布尔值 |
sequence | 用于设置自增序列名 | 字符串 |
replace | 用于设置使用REPLACE方式写入 | 布尔值 |
extra | 用于设置额外查询规则 | 字符串 |
duplicate | 用于设置DUPLCATE信息 | 数组 字符串 |
procedure | 用于设置当前查询是否为存储过程查询 | 布尔值 |
master | 用于设置主服务器读取数据 | 布尔值 |
view* | 用于视图查询 | 字符串、数组 |
十五、事务操作
InnoDB
引擎支持事务处理,MyISAM
不支持事务处理
// 启动事务Db::startTrans();$data = ['cat'=>'1','title'=>'日系小浪漫与温暖羊毛针织拼接网纱百褶中长收腰连衣裙','price'=>'1598.35','add_time'=>1576080000];$insert = Db::table('shop_goods')->insert($data);if(empty($insert)){ // 回滚事务 Db::rollback();}else{ // 提交事务 Db::commit();}
transaction
方法操作数据库事务,当闭包中的代码发生异常会自动回滚
Db::transaction(function () { $data = ['cat'=>'1','title'=>'日系小浪漫与温暖羊毛针织拼接网纱百褶中长收腰连衣裙','price'=>'1598.35','add_time'=>1576080000]; $insert = Db::table('shop_goods')->insert($data);});
十六、数据集
数据库通过select查询,得到的数据集对象
返回的数据集对象是
think\Collection
,提供了和数组无差别用法,并且另外封装了一些额外的方法
编号 | 方法 | 描述 |
---|---|---|
1 | isEmpty | 是否为空 |
2 | toArray | 转换为数组 |
3 | all | 所有数据 |
4 | merge | 合并其它数据 |
5 | diff | 比较数组,返回差集 |
6 | flip | 交换数据中的键和值 |
7 | intersect | 比较数组,返回交集 |
8 | keys | 返回数据中的所有键名 |
9 | pop | 删除数据中的最后一个元素 |
10 | shift | 删除数据中的第一个元素 |
11 | unshift | 在数据开头插入一个元素 |
12 | push | 在结尾插入一个元素 |
13 | reduce | 通过使用用户自定义函数,以字符串返回数组 |
14 | reverse | 数据倒序重排 |
15 | chunk | 数据分隔为多个数据块 |
16 | each | 给数据的每个元素执行回调 |
17 | filter | 用回调函数过滤数据中的元素 |
18 | column | 返回数据中的指定列 |
19 | sort | 对数据排序 |
20 | order | 指定字段排序 |
21 | shuffle | 将数据打乱 |
22 | slice | 截取数据中的一部分 |
23 | map | 用回调函数处理数组中的元素 |
24 | where | 根据字段条件过滤数组中的元素 |
25 | whereLike | Like查询过滤元素 |
26 | whereNotLike | Not Like过滤元素 |
27 | whereIn | IN查询过滤数组中的元素 |
28 | whereNotIn | Not IN查询过滤数组中的元素 |
29 | whereBetween | Between查询过滤数组中的元素 |
30 | whereNotBetween | Not Between查询过滤数组中的元素 |
$select = Db::table('shop_goods') ->field('title,price,id') ->where('status',1) ->order('price','DESC') ->select();if($select->isEmpty()){ echo '未查询到数据';}else{ print_r($select->toArray());}
备:在模型中进行数据集查询,全部返回数据集对象,但使用的是think\model\Collection类
(继承think\Collection),但用法是一致的。