本学习课程以学习为目的一周三篇持续更新,学习代码更新在码云公开仓库,不足之处欢迎朋友们前来指导,写作不易请多多支持,本人创作新手写的不好,不喜勿喷,谢谢大家。
学习目标
- 单条数据查询
- 查询数据集
- 值和列查询
- 海量数据优化查询
- 查询规则
- 查询对象保存调用(相当于单例)
一.单条数据查询
码云提交编号:10921f8cd191d1caa45c03e53af52a472845ad0a
- 首先贴一下数据库表以便配套代码(不需要可以忽略),当然大家也可以自己创建啊
CREATE DATABASE `tp60-learning` ;USE `tp60-learning`;DROP TABLE IF EXISTS `tp_user`;CREATE TABLE `tp_user` ( `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT COMMENT '自动编号', `username` varchar(20) NOT NULL COMMENT '用户名', `password` char(40) NOT NULL COMMENT '密码', `gender` char(1) NOT NULL DEFAULT '1' COMMENT '性别', `email` varchar(50) DEFAULT NULL COMMENT '邮箱', `remarks` text NOT NULL COMMENT '备注', `status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '状态', `delete_time` datetime DEFAULT NULL, `create_time` datetime NOT NULL COMMENT '创建时间', `update_time` datetime NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; LOCK TABLES `tp_user` WRITE;insert into `tp_user`(`id`,`username`,`password`,`gender`,`email`,`remarks`,`status`,`delete_time`,`create_time`,`update_time`) values (1,'反贼唐三','e10adc3949ba59abbe56e057f20f883e','1','123@qq.com','老铁66',0,NULL,'2022-03-23 20:09:27','2022-03-23 20:09:27'),(2,'张三','e10adc3949ba59abbe56e057f20f883e','1','123@qq.com','老铁66',0,NULL,'2022-03-23 20:09:27','2022-03-23 20:09:27'),(3,'李四','e10adc3949ba59abbe56e057f20f883e','1','123@qq.com','老铁66',0,NULL,'2022-03-23 20:09:27','2022-03-23 20:09:27'),(4,'王二','e10adc3949ba59abbe56e057f20f883e','1','123@qq.com','老铁66',0,NULL,'2022-03-23 20:09:27','2022-03-23 20:09:27'),(5,'码字','e10adc3949ba59abbe56e057f20f883e','1','123@qq.com','老铁66',0,NULL,'2022-03-23 20:09:27','2022-03-23 20:09:27'),(6,'赵六','e10adc3949ba59abbe56e057f20f883e','1','123@qq.com','老铁66',0,NULL,'2022-03-23 20:09:27','2022-03-23 20:09:27');UNLOCK TABLES;
- Db::table()中 table 必须指定完整数据表(包括前缀)
-
如果希望只查询一条数据,可以使用 find() 方法,需指定 where 条件
<?phpnamespace app\controller;use think\facade\Db;class DatabaseSite { public function index(){ $user = Db::table('tp_user')->where('id',1)->find(); return json($user); }}
-
Db::getLastSql() 方法,可以得到最近一条 SQL 查询的原生语句,没有查询到结果会返回null
$user = Db::table('tp_user')->where('id',1)->find(); // return json($user); return Db::getLastSql(); // 得到的结果是 // SELECT * FROM `tp_user` WHERE `id` = 1 LIMIT 1
-
使用 findOrFail() 方法同样可以查询一条数据,在没有数据时抛出一个异常
$user = Db::table('tp_user')->where('id',100)->findOrFail(); return json($user);
- 使用 findOrEmpty()方法也可以查询一条数据,但在没有数据时返回一个空数组
$user = Db::table('tp_user')->where('id',100)->findOrEmpty(); return json($user);
二.查询数据集
- 想要获取多列数据,可以使用 select()方法,获取所有数据
$user = Db::table('tp_user')->select(); return json($user);
- 多列数据在查询不到任何数据时返回空数组,使用 selectOrFail()抛出异常
$user = Db::table('tp_user')->where('gender',2)->selectOrFail(); return json($user);
- 在 select()方法后再使用 toArray()方法,可以将数据集对象转化为数组
$user = Db::table('tp_user')->select()->toArray(); dump($user);
- 当在数据库配置文件中设置了前缀,那么我们可以使用 name()方法忽略前缀
$user = Db::name('user')->select(); return json($user);
三.值和列查询
-
通过 value() 方法,可以查询指定字段的值(单个),没有数据返回 null
$user = Db::name('user')->where('id', 1)->value('username'); return $user;
-
通过 colunm()方法,可以查询指定列的值(多个),没有数据返回空数组,可以指定 id 作为列值的索引
$user =Db::name('user')->column('username','id'); return json($user);
四.海量数据优化查询
-
如果处理的数据量巨大,成千上万那种,一次性读取有可能会导致内存开销过大,为了避免内存处理太多数据出错,可以使用 chunk() 方法分批处理数据
-
该方法一次获取结果集的一小块,然后填充每一小块数据到要处理的闭包,该方法在编写处理大量数据库记录的时候非常有用
- 这里配置一个数据库mysql3并用连接connect('mysql3'),分批处理goods表前100000条数据,每次处理1000条,
- 为了验证他真的是每次只处理1000条数据 ,我们用echo "每处理1000数据后,输出标记点"
Db::connect('mysql3')->table('goods')->where('id','<',100000)->chunk(1000, function($users) { foreach ($users as $user) { echo $user['id']."**"; } echo "每处理10000数据后,输出标记点"; });
- 接下来验证他是否真的能节省内存开销,我们以相同的条件和操作,写一个select查询,
//chunk测试 Db::connect('mysql3')->table('goods')->where('id','<',100000)->chunk(1000, function($users) { foreach ($users as $user) { echo $user['id']."**"; }});//select测试 $users = Db::connect('mysql3')->table('goods')->where('id','<',100000)->select(); foreach ($users as $user) { echo $user['id']."**"; }
-
你可以通过从闭包函数中返回
false
来中止对后续数据集的处理Db::connect('mysql3')->table('goods')->where('id','<',100000)->chunk(1000, function($users) { foreach ($users as $user) { if($user['id']==1003){ return false; } echo $user['id']."--"; echo $user['name']."<br>"; } echo "每处理10000数据后,输出标记点"; });
-
chunk
方法的处理默认是根据主键查询,支持指定字段,并且支持指定处理数据的顺序Db::connect('mysql3')->table('goods')->where('id','<',1000)->chunk(10, function($users) { foreach ($users as $user) { if($user['id']==15){ return false; } // echo $user['id']."--"; // echo $user['name']."<br>"; dump($user); } echo "每处理10000数据后,输出标记点"; },'id', 'desc');
-
果你需要处理大量的数据,可以使用新版提供的游标查询功能,该查询方式利用了PHP的生成器特性,可以大幅减少大量数据查询的内存开销问题。
-
它每次查询只读取一行数据,然后再读取时,自动定位到下一行继续读取,
$cursor = Db::table('user')->where('status', 1)->cursor(); foreach($cursor as $user){ echo $user['name']; }
- 那我们测试一下他的内存占用情况,写一个select查询和cursor查询,和相同的遍历输出操作
//select查询 $users = Db::connect('mysql3')->table('goods')->where('id','<',100000)->select(); foreach ($users as $user) { echo $user['id']."**<br>"; } //游标查询 $users = Db::connect('mysql3')->table('goods')->where('id','<',100000)->cursor(); foreach ($users as $user) { echo $user['id']."**<br>"; }
五.查询规则
码云提交编号:b5beec6d4b35649ac274d7d5e71bd72b7f2ccb6f
-
前面课程中我们通过指向符号“ -> ”多次连续调用方法称为:链式查询
-
当 Db::name('user') 时,返回查询对象 (Query) ,即可连缀数据库对应的方法
$users = Db::connect('mysql3')->table('goods'); dump($users);
^ think\db\Query {#52 ▼ #connection: think\db\connector\Mysql {#50 ▶} #name: "" #pk: null #autoinc: null #prefix: "tp_" #options: array:1 [▼ "table" => "goods" ] #timeRule: array:8 [▼ "today" => array:2 [▶] "yesterday" => array:2 [▶] "week" => array:2 [▶] "last week" => array:2 [▶] "month" => array:2 [▶] "last month" => array:2 [▶] "year" => array:2 [▶] "last year" => array:2 [▶] ] #model: null #bind: [] }
-
而每次执行一个数据库查询方法时,比如 where() ,还将返回查询对象 (Query)
$users = Db::connect('mysql3')->table('goods')->where('id','<',3); dump($users);
^ think\db\Query {#52 ▼ #connection: think\db\connector\Mysql {#50 ▶} #name: "" #pk: null #autoinc: null #prefix: "tp_" #options: array:2 [▼ "table" => "goods" "where" => array:1 [▼ "AND" => array:1 [▼ 0 => array:4 [▼ 0 => "id" 1 => "<" 2 => 100000 3 => null ] ] ] ] #timeRule: array:8 [▶] #model: null #bind: [] }
-
只要还是数据库对象,那么就可以一直使用指向符号进行链式查询
-
再利用 find() 、 select() 等方法返回数组 (Array) 或数据集对象 (Colletion)
$users = Db::connect('mysql3')->table('goods')->where('id','<',3)->select(); dump($users);
^ think\Collection {#53 ▼ #items: array:2 [▼ 0 => array:14 [▶] 1 => array:14 [▼ "id" => 2 "name" => "将很快" "category_id" => 2 "store_id" => 2 "status" => 0 "use_flag" => 0 "create_time" => "2020-12-12 00:00:00" "update_time" => "2021-12-13 00:00:00" "up_time" => "2022-12-12 00:00:00" "down_time" => "0000-00-00 00:00:00" "description" => "12321" "keywords" => "121" "min_price" => "121" "max_price" => "2121" ] ] }
$users = Db::connect('mysql3')->table('goods')->where('id','<',3)->find(); dump($users);
^ array:14 [▼ "id" => 1 "name" => "12" "category_id" => 2 "store_id" => null "status" => null "use_flag" => null "create_time" => null "update_time" => null "up_time" => null "down_time" => null "description" => null "keywords" => null "min_price" => null "max_price" => null ]
六.查询对象保存调用(相当于单例)
-
如果多次使用数据库查询,那么每次静态创建都会生成一个实例,造成浪费,但我们可以把对象实例保存下来,再进行反复调用即可;
$sqlquery = Db::name('user'); $dataFind = $sqlquery->where('id', '<',5)->find(); $dataSelect = $sqlquery->select();
- 但是,当同一个对象实例第二次查询后,会保留第一次查询的值,我们
$sqlquery = Db::name('user'); $dataFind = $sqlquery->where('id', '<',5)->find(); $dataSelect = $sqlquery->select(); return Db::getlastSql();
SELECT * FROM `tp_user` WHERE `id` < 5
这里有一个where条件,但是我们进行select查询时并没有执行where操作
- 使用 removeOption()方法,可以清理掉上一次查询保留的值
$sqlquery = Db::name('user'); $dataFind = $sqlquery->where('id', '<',5)->find(); $dataSelect = $sqlquery->removeOption('where')->select(); return Db::getlastSql();
SELECT * FROM `tp_user`
-
removeOption()方法,
/** * 去除查询参数 * @access public * @param string $option 参数名 留空去除所有参数 * @return $this */
发表评论 取消回复