9.ThinkPHP数据库操作
连接数据库
在应用配置目录或者模块配置目录下面的config/database.php中配置下面的数据库参数
注:配置好的,一定要检查mysql服务是否开启,同时也要检查pdo是否打开。
同时还是创建好对应的数据库和连接数据库的用户名和密码并确保他们可以连接上你们的mysql服务器。
读取配置文件中的配置
例:
<?php namespace app\index\controller; use think\Controller; class Db extends Controller { public function db(){ //database文件中的prefix选项 echo config(‘database.prefix‘); } }
访问结果
执行原生的sql
db类查询方法
Db
类支持原生SQL
查询操作,主要包括下面两个方法:
方法名 | 作用 |
---|---|
query 方法 | query 方法用于执行SQL 查询操作,如果数据非法或者查询错误则返回false,否则返回查询结果数据集(同select 方法) |
execute 方法 | 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]);
用法示例
方式一
<?php namespace app\index\controller; use think\Controller; use \think\Db as mdb; class Db extends Controller { public function db(){ //?为占位符 $sql = "select * from tp_articles where id=?"; $res = mdb::query($sql,[102]); dump($res); } }
方式二
<?php namespace app\index\controller; use think\Controller; //注意引入会报错所以重命名一下 use \think\Db as mdb; class Db extends Controller { public function db(){ //:id为占位符 //如果一定要写原生sql,推荐写此关联数组占位 $sql = "select * from tp_articles where id=:id"; $res = mdb::query($sql,[‘id‘ => 102]); dump($res); } }
以上两种方式运行结果为:
添加数据
单条数据插入
要添加的数据
$data = [‘title‘ => ‘我是标题111‘, ‘desn‘ => ‘我是描述‘, ‘body‘ => ‘bbbb‘];
注意:方式一和方式二都要引入\think\Db
例:
use \think\Db;
方式一:Db::table 需要写全表名称
例:
// 添加一条数据 // 返回影响的行数 // table写全表名称 $ret = Db::table(‘tp_articles‘)->insert($data);
方式二:Db::name 可以不写前缀
// name可以不写表前缀 $ret = Db::name(‘articles‘)->insert($data);
方式三:db()可以不写前缀,也不用引入db类
$ret = db(‘articles‘) -> insert($data) ;
注意上面三种运行后返回的都是影响的行数
运行结果
返回插入成功的主键ID
$ret = db(‘articles‘) -> insertGetId($data) ;
运行结果
多条数据插入
要添加的数据
# 添加多条数据 $data = [ [‘title‘ => ‘1111‘, ‘body‘ => ‘aaa‘], [‘title‘ => ‘2222‘, ‘body‘ => ‘bbb‘], [‘title‘ => ‘3333‘, ‘body‘ => ‘ccc‘] ];
方式一:Db::name(‘表名‘)->insertAll($data)
//先引入 use \think\Db; $res = Db::name(‘articles‘)->insertAll($data);
方式二:db(‘表名‘)->insertAll($data)
$res = db(‘articles‘)->insertAll($data);
更新数据
全字段更新
方式一:db()->where()->update()方式
写法示例:
#写法1 推荐 注意如果where条件中间是=号,则可以省略不写 db(‘user‘)->where(‘id‘, ‘=‘, 205)->update([‘name‘ => ‘thinkphp‘]); #写法2 db(‘user‘)->where(‘id‘, ‘=‘, 205)->data([‘name‘ => ‘thinkphp‘])->update(); #写法3 这种写法需要主键是id Db::name(‘user‘)->update([‘name‘ => ‘thinkphp‘,‘id‘=>1]);
例:
public function update(){ // 修改数据 $data = [‘title‘ => ‘我是标题111‘, ‘desn‘ => ‘我是描述‘, ‘body‘ => ‘bbbb‘]; //$res = db(‘articles‘)->where(‘id‘, ‘=‘, ‘205‘)->update($data); $data = [‘id‘ => ‘205‘,‘title‘ => ‘我是标题111‘, ‘desn‘ => ‘我是描述‘, ‘body‘ => ‘bbbb‘]; $res = db(‘articles‘)->update($data); dump($res); }
运行结果
方式二:Db::raw 数值类型字段更新
V5.1.7+
版本以后,支持使用raw
方法进行数据更新,适合在数组更新的情况。
注意Db::raw支持表达式,字符串是用Db::raw 相当于值没有加引号的情况,最好是数值类型的
写法示例:
Db::name(‘user‘) ->where(‘id‘, 1) ->update([ ‘name‘ => Db::raw(‘UPPER(name)‘), ‘score‘ => Db::raw(‘score-3‘), ‘read_time‘ => Db::raw(‘read_time+1‘) ]);
例:
$res = Db::name(‘articles‘) ->where(‘id‘,206) ->update([ ‘click‘ => Db::raw(‘click+1‘) ]);
运行结果
单字段更新
setField() 更新单个字段
Db::name(‘user‘) ->where(‘id‘,1) ->setField(‘name‘, ‘thinkphp‘);
最终生成的SQL语句可能如下:
UPDATE `think_user` SET `name` = ‘thinkphp‘ WHERE `id` = 1
setField 方法返回影响数据的条数,没修改任何数据字段返回 0
setInc/setDec 自增或自减一个字段的值
可以使用setInc/setDec
方法自增或自减一个字段的值( 如不加第二个参数,默认步长为1)。
// score 字段加 1 Db::table(‘think_user‘) ->where(‘id‘, 1) ->setInc(‘score‘); // score 字段加 5 Db::table(‘think_user‘) ->where(‘id‘, 1) ->setInc(‘score‘, 5); // score 字段减 1 Db::table(‘think_user‘) ->where(‘id‘, 1) ->setDec(‘score‘); // score 字段减 5 Db::table(‘think_user‘) ->where(‘id‘, 1) ->setDec(‘score‘, 5);
最终生成的SQL语句可能是:
UPDATE `think_user` SET `score` = `score` + 1 WHERE `id` = 1 UPDATE `think_user` SET `score` = `score` + 5 WHERE `id` = 1 UPDATE `think_user` SET `score` = `score` - 1 WHERE `id` = 1 UPDATE `think_user` SET `score` = `score` - 5 WHERE `id` = 1
setInc/setDec
支持延时更新,如果需要延时更新则传入第三个参数,下例中延时10秒更新。
Db::name(‘user‘)->where(‘id‘, 1)->setInc(‘score‘, 1, 10);
setInc/setDec 方法返回影响数据的条数,如果使用了延迟更新的话,可能会返回true
删除数据
删除写法示例
# 根据主键删除 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(); # 无条件删除所有数据 小心去用 Db::name(‘user‘)->delete(true); # 软删除数据 使用delete_time字段标记删除 逻辑删除 # 软删除,必须要表中要delete_time字段,且该字段因为存放的是时间戳所以应该是int Db::name(‘user‘) ->where(‘id‘, 1) ->useSoftDelete(‘delete_time‘,time()) ->delete();
直接删除示例
软删除示例
public function del(){ # 软删除数据 使用delete_time字段标记删除 逻辑删除 # 软删除,必须要表中要delete_time字段 且该字段因为存放的是时间戳所以应该是int $res = Db::name(‘articles‘) ->where(‘id‘, 207) ->useSoftDelete(‘delete_time‘,time()) ->delete(); dump($res); }
查询数据
相关方法API和作用
方法 | 作用 | 示例 |
---|---|---|
find() | 查询单个数据 | // table方法必须指定完整的数据表名 Db::table(‘think_user‘)->where(‘id‘,1)->find(); |
findOrFail() | 如果希望在没有找到数据后抛出异常可以使用 | 如果没有查找到数据,则会抛出一个think\db\exception\DataNotFoundException 异常Db::table(‘think_user‘)->where(‘id‘,1)->findOrFail(); |
findOrEmpty() | V5.1.23+ 版本开始,支持,当查询不存在的时候返回空数组而不是Null | Db::table(‘think_user‘)->where(‘id‘,1)->findOrEmpty() |
select() | 查询多个数据(数据集)使用 | Db::table(‘think_user‘)->where(‘status‘,1)->select() |
selectOrFail() | 如果希望在没有查找到数据后抛出异常可以使用 | 如果没有查找到数据,同样也会抛出一个think\db\exception\DataNotFoundException 异常Db::table(‘think_user‘)->where(‘status‘,1)->selectOrFail() |
value() | 查询某个字段的值可以用,value 方法查询结果不存在,返回 null | // 返回某个字段的值 Db::table(‘think_user‘)->where(‘id‘,1)->value(‘name‘); |
column() | 查询某一列的值可以用,column 方法查询结果不存在,返回空数组 | // 返回数组 Db::table(‘think_user‘)->where(‘status‘,1)->column(‘name‘); // 指定id字段的值作为索引,也就是让id作为键name为值 Db::table(‘think_user‘)->where(‘status‘,1)->column(‘name‘,‘id‘); // 指定id字段的值作为索引 返回所有数据 Db::table(‘think_user‘)->where(‘status‘,1)->column(‘*‘,‘id‘); |
order() | 排序 | |
limit() | 取某个范围的值 |
单条件查询
注意:上面的方法都能用,这里只是做个例子
例:
public function select(){ //$res = db(‘articles‘)->where(‘id‘,‘=‘, 102)->find(); $res = db(‘articles‘)->where(‘id‘,‘>‘, 200)->select(); dump($res); }
多条件查询
例:
public function select(){ //id 大于100,click大于100 //方式一 //$res = db(‘articles‘)->where(‘id‘,‘>‘, 100)->where(‘click‘, ‘>‘, 100)->select(); //方式二 /*$where = [ [‘id‘, ‘>‘, 100], [‘click‘, ‘>‘, 100] ]; $res = db(‘articles‘)->where($where)->select();*/ //方式三 /*$where = [ ‘id‘ => [‘>‘, 100], ‘click‘ => [‘>‘, 100] ]; $obj = new Where($where); $res = db(‘articles‘)->where($obj)->select();*/
//方式四 闭包查询 //注意:这种方式sql会解析成这样,进行了条件分组 //如:SELECT * FROM `tp_articles` WHERE ( `id` > 100 AND `click` > 100 ) OR ( `id` > 100 AND `click` > 100 ) //上面的三种方式则不会,会直接解析成,没有进行条件分组 //如: SELECT * FROM `tp_articles` WHERE `id` > 100 AND `click` > 100 $res = db(‘articles‘)->where(function (Query $query){ $query->where(‘id‘,‘>‘, 100)->where(‘click‘, ‘>‘, 100); })->whereOr(function (Query $query){ $query->where(‘id‘,‘>‘, 100)->where(‘click‘, ‘>‘, 100); })->select(); dump($res); }
where条件 and,or,in
where
方法的用法是ThinkPHP查询语言的精髓,也是ThinkPHP ORM
的重要组成部分和亮点所在,可以完成包括普通查询、表达式查询、快捷查询、区间查询、组合查询在内的查询操作。where
方法的参数支持的变量类型包括字符串、数组和闭包。
和
where
方法相同用法的方法还包括whereOr
、whereIn
等一系列快捷查询方法,下面仅以where
为例说明用法。
AND
主要用于等值AND
条件,例如:
// 传入数组作为查询条件 Db::table(‘think_user‘)->where([ ‘name‘ => ‘thinkphp‘, ‘status‘=> 1 ])->select();
最后生成的SQL语句是
SELECT * FROM think_user WHERE `name`=‘thinkphp‘ AND status = 1
IN
V5.1.13+
版本开始增加了关联数组的IN
查询支持,例如可以使用:
// 传入数组作为查询条件 Db::table(‘think_user‘)->where([ ‘name‘ => ‘thinkphp‘, ‘status‘=> [1, 2] ])->select();
最后生成的SQL语句是
SELECT * FROM think_user WHERE `name`=‘thinkphp‘ AND status IN (1, 2)
OR
$res = db(‘articles‘)->where(function (Query $query){ $query->where(‘id‘,‘>‘, 100)->where(‘click‘, ‘>‘, 100); })->whereOr(function (Query $query){ $query->where(‘id‘,‘>‘, 100)->where(‘click‘, ‘>‘, 100); })->select();
最后生成的SQL语句是
SELECT * FROM `tp_articles` WHERE ( `id` > 100 AND `click` > 100 ) OR ( `id` > 100 AND `click` > 100 )
字符串条件
使用字符串条件直接查询和操作,例如:
Db::table(‘think_user‘)->where(‘type=1 AND status=1‘)->select();
最后生成的SQL语句是
SELECT * FROM think_user WHERE type=1 AND status=1
注意使用字符串查询条件和表达式查询的一个区别在于,不会对查询字段进行避免关键词冲突处理。
使用字符串条件的时候,如果需要传入变量,建议配合预处理机制,确保更加安全,例如:
Db::table(‘think_user‘) ->where("id=:id and username=:name", [‘id‘ => [1, \PDO::PARAM_INT] , ‘name‘ => ‘thinkphp‘]) ->select();
或者使用
Db::table(‘think_user‘) ->where("id=:id and username=:name") ->bind([‘id‘ => [1, \PDO::PARAM_INT] , ‘name‘ => ‘thinkphp‘]) ->select();
在V5.1.7+
版本以后,你可以使用更安全的
Db::table(‘think_user‘) ->whereRaw("id=:id and username=:name", [‘id‘ => [1, \PDO::PARAM_INT] , ‘name‘ => ‘thinkphp‘]) ->select();
排序和分页
$res = db(‘articles‘)->order(‘id‘, ‘desc‘)->limit(0,2)->select();
例:
聚合查询
在应用中我们经常会用到一些统计数据,例如当前所有(或者满足某些条件)的用户数、所有用户的最大积分、用户的平均成绩等等,ThinkPHP为这些统计操作提供了一系列的内置方法,包括:
方法 | 说明 |
---|---|
count | 统计数量,参数是要统计的字段名(可选) |
max | 获取最大值,参数是要统计的字段名(必须) |
min | 获取最小值,参数是要统计的字段名(必须) |
avg | 获取平均值,参数是要统计的字段名(必须) |
sum | 获取总分,参数是要统计的字段名(必须) |
聚合方法如果没有数据,默认都是0,聚合查询都可以配合其它查询条件
V5.1.5+
版本开始,聚合查询可以支持JSON
字段类型
用法示例
获取用户数:
Db::table(‘think_user‘)->count();
实际生成的SQL语句是:
SELECT COUNT(*) AS tp_count FROM `think_user` LIMIT 1
或者根据字段统计:
Db::table(‘think_user‘)->count(‘id‘);
生成的SQL语句是:
SELECT COUNT(id) AS tp_count FROM `think_user` LIMIT 1
获取用户的最大积分:
Db::table(‘think_user‘)->max(‘score‘);
生成的SQL语句是:
SELECT MAX(score) AS tp_max FROM `think_user` LIMIT 1
如果你要获取的最大值不是一个数值,可以使用第二个参数关闭强制转换
Db::table(‘think_user‘)->max(‘name‘,false);
获取积分大于0的用户的最小积分:
Db::table(‘think_user‘)->where(‘score‘, ‘>‘, 0)->min(‘score‘);
和max方法一样,min也支持第二个参数用法
Db::table(‘think_user‘)->where(‘score‘, ‘>‘, 0)->min(‘name‘,false);
获取用户的平均积分:
Db::table(‘think_user‘)->avg(‘score‘);
生成的SQL语句是:
SELECT AVG(score) AS tp_avg FROM `think_user` LIMIT 1
统计用户的总成绩:
Db::table(‘think_user‘)->where(‘id‘,10)->sum(‘score‘);
生成的SQL语句是:
SELECT SUM(score) AS tp_sum FROM `think_user` LIMIT 1
获取器(V5.1.20+
)
Db类也可以支持获取器定义,例如:
Db::name(‘user‘)->withAttr(‘name‘, function($value, $data) { return strtolower($value); })->select();
上面的代码,查询的数据集数据中的name
字段的值会统一进行小写转换。
withAttr
方法可以多次调用,对多个字段定义获取器。
支持对JSON字段定义获取器,例如:
$user = Db::name(‘user‘) ->json([‘info‘]) ->withAttr(‘info.name‘, function($value, $data) { return strtolower($value); })->find(1); dump($user);
查询结果返回的时候,会自动对info
字段(JSON
字段)的name
属性使用获取器操作。
例:
//获取器 当前数据,数据源 $res = db(‘articles‘)->withAttr(‘title‘,function ($value,$data){ //重新编辑的数据 return ‘获取器-----‘.$value; })->where(‘id‘,‘>‘, 200)->select();
运行结果