ThinkPHP数据库操作
Mirror王宇阳
建议参考官方文档
数据库配置文件
config\database.php
是thinkphp的数据库配置文件,在开发环境中该数据库文件主要是根据.Env
文件,迁入到生产环境后.Env
需要被忽略。
default
配置用于设置默认使用的数据库连接配置。
connections
配置具体的数据库连接信息,default
配置参数定义的连接配置必须要存在。
创建数据库连接
namespace app\controller;
use think\facade\Db;
class DataTest
{
public function index()
{
$user = Db::table('tp_user')->select();
return json($user);
}
}
数据库操作
Db
是thinkphp封装的数据库操作方法,调用需要use think\facade\Db
Db::getLastSql()
:返回最近一次的sql执行语句
数据查询
find()
方法:查询表中单个数据,存在则返回否则返回null
# 查询tp_user数据表中的单个数据
return json(
Db::table('tp_user')// 如何设置了表前缀可以忽略tp_
->where('id',20)
->find()
);
# select * from `tp_user` where `id` = 20 limit 1
findOrEmpty()
方法:不存在数据返回空数组,不返回null
findOrFail()
方法:不存在抛出DataNotFoundException
异常
select()
方法:查询表中多个数据,存在返回否则返回null
return json(
Db::table('tp_user')
->select()
);
toArray()
方法:将select()
返回的数据集对象转为数组在不使用
json
时,select()
返回的只是一个数据集对象,json
转换了对象为json
selectOrFail()
:不存在抛出DataNotFoundException
异常
find()
和select()
是最终的输出,在输出前可以使用各式各样的链式操作
指定列column()
/值value()
查询
-
指定查询某一列的数据内容
return json( Db::table('tp_user') ->column('username') );
-
指定查询某一值(通过条件约束查询字段值)
return json( Db::table('tp_user') ->where('username','路飞') ->value('password') // 查询(username)路飞的密码(password) );
数据分批处理:chunk()
,可以将大量的数据结果(集)进行一定范围的截取
比如,我们可以全部用户表数据进行分批处理,每次处理 100 个用户记录:
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;
}
}
});
也支持在chunk
方法之前调用其它的查询方法,例如:
Db::table('think_user')
->where('score','>',80)
->chunk(100, function($users) {
foreach ($users as $user) {
//
}
});
chunk
方法的处理默认是根据主键查询,支持指定字段,例如:
Db::table('think_user')->chunk(100, function($users) {
// 处理结果集...
return false;
},'create_time');
并且支持指定处理数据的顺序。
Db::table('think_user')->chunk(100, function($users) {
// 处理结果集...
return false;
},'create_time', 'desc');
chunk
方法一般用于命令行操作批处理数据库的数据,不适合WEB访问处理大量数据,很容易导致超时。
游标查询cursor()
利用文件PHP生成器特性,每次查询只读取一行,然后再读取速度时自动定位到下一行继续读取
$cursor = Db::table('tp_user')->cursor();
foreach($cursor as $user){
dump($user);
// dump():thinkphp自带的一种打印调试函数
}
相关补充:
使用->
将多种查询方法、条件进行链式组合;
Db::table('tp_user')
返回的是查询对象Q;当一个查询对象第二次查询会保留第一次查询值或条件,可以使用removeOption()
方法清除查询对象缓存的查询条件和值
数据添加
insert()
:添加一条数据,成功添加返回'1'
$data = [
'username' => '柯南',
'password' => '0504',
'gender' => '男',
'email' => '[email protected]',
'price' => 10,
'details' => '112',
];
return json(Db::table('tp_user')->insert($data));
如果添加的字段与数据表中的字段不符合,系统会抛出异常;强行添加不存在的字段数据可以使用strick(false)
忽略异常信息
replace()
:【仅支持mysql数据库】会修改有错误的字段名
insertGetId()
:添加成功返回新增数据的主键ID
insertAll()
:添加多条数据,返回成功添加的数据条数
public function index()
{
$data = [
[
'username' => '柯南',
'password' => '0504',
'gender' => '男',
'email' => '[email protected]',
'price' => 10,
'details' => '112',
],
[
'username' => '小哀',
'password' => '1214',
'gender' => '女',
'email' => '[email protected]',
'price' => 10,
'details' => '192',
],
[
'username' => '小兰',
'password' => '3344',
'gender' => '女',
'email' => '[email protected]',
'price' => 18,
'details' => '202',
],
];
return Db::table('tp_user')->insertAll($data);
}
save()
:通用的写入方法,可以自动的判断当前的数据操作是添加或者修改(更新);通过判断是否存在主键判断。
数据修改(更新)
updata()
:修改数据,返回成功修改的行数否则返回0
$data = [
'username' => '琴酒',
];
Db::table('tp_user')
->where('id',302)
->update($data);
return Db::getLastSql();
// UPDATE `tp_user` SET `username` = '琴酒' WHERE `id` = 302
在更新的数据
$data
中添加主键id,可以省略掉where()
$data = [
'id' => 302 ,
'username' => '琴酒',
];
Db::table('tp_user')
->update($data);
return Db::getLastSql();
使用
save()
方法也可以更新带有主键ID的数据
$data = [
'id' => 302 ,
'username' => '琴酒',
];
Db::table('tp_user')
->save($data);
return Db::getLastSql();
支持使用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')
]);
raw()
:raw的单词原义是“原生”,也就是
Db::raw(***)
中的字符串会被认为原生的sql语义
自增inc()
/自减dec()
// 默认步长为'1'
inc('字段名','步长');
dec('字段名','步长');
Db::table('tp_user')
->where('id',302)
->inc('price',5)
->update();
Db::table('tp_user')
->where('id',302)
->dec('price',10)
->update();
数据删除
delete()
:数据删除
// 通过主键ID删除数据
Db::table('tp_user')->delete(306);
// 支持数组
Db::table('tp_user')->delete([306,307,308]);
// 通过where条件删除
Db::table('tp_user')->where('id',307)->delete();
// 删除所有数据(清空数据表)
Db::table('tp_user')->delete(true);
在业务数据中使用软删除(将数据的ID标记删除,使用新的内容覆盖ID标记)
查询表达式
比较查询
where('字段名','[表达式]','查询条件');
where()
有三个参数值,第二个参数可忽略(普通表达式有:>
<
=
<>
<=
>=
),参数空缺是默认为=
,支持数组传递和字符串传递;第三个参数查询条件支持数组传递条件值;第四个参数是基于第三个参数采用数组传递条件值,使用或与非来决定多个条件之间的逻辑关系
区间查询
like()/not like()
根据指定的模糊条件查询匹配
-
模糊查询
Db::table('tp_user') ->where('email','like','xiao%') ->select() //====================================// Db::table('tp_user') // 多个查询条件,数组传递 ->where('email','like',['xiao%','ke%'],'OR') //whereOr('email','like',['xiao%','ke%']) ->select()
%
:模糊匹配多个字符*
:模糊匹配单个字符快捷方法=>
whereLink()
/whereNoLink()
Db::table('tp_user')
->whereLike('email','xiao%')
->select()
//=============================//
Db::table('tp_user')
->whereNotLike('email','xiao%')
->select()
between()/not between()
查询条件支持的字符串或数组,指定查询一个范围内的数据,接收两个参数一个起始点另一个终止点。
Db::table('tp_user')
->where('id','between','301,304')
// 同时也支持数组传递
->select()
等效于
SELECT * FROM `tp_user` WHERE `id` BETWEEN 301 AND 304
快捷方式:
whereBetween()
/whereNotBetween()
in()/not in()
查询条件支持的字符串或数组,精确指定查询的位置。
Db::table('tp_user')
->where('id','in','301,302,303')
// 同时也支持数组传递
->select()
等效于
SELECT * FROM`tp_user` WHERE`id` IN(301,302,303)
快捷方式:
whereIn()
/whereNotIn()
Null()/not Null()
:判断字段是否为空
快捷方式:
whereNull()
/whereNotNull()
exp:表达式
exp
支持复杂的查询表达式构造
Db::table('tp_user')
->where('id','in','301,302,303')
->select();
Db::table('tp_user')
->where('id','exp','IN (301,302,303)')
->select();
exp
查询的条件不会被当成字符串,会被视为一个查询表达式,支持sql语法的函数和字段
快捷方式:
whereExp()
时间查询
-
传统方式:
where()
基本表达式可以进行基本时间查询Db::table('tp_user') ->where('create_time','>','2018-01-01') ->select();
SELECT * FROM `tp_user` WHERE `create_time` > '2018-01-01'
between()
设置时间查询的区间Db::table('tp_user') ->where('create_time','between','2018-01-01,2020-01-01') ->select();
SELECT * FROM `tp_user` WHERE `create_time` BETWEEN '2018-01-01' AND 2020-01-01'
-
快捷查询:
whereTime()
可以直接使用普通表达式符号Db::table('tp_user') ->whereTime('create_time','>','2018-01-01') ->select();
whereBetweenTime()/whereNotBetweenTime()
区间查询时间Db::table('tp_user') ->whereBetweenTime('create_time','2018-01-01,2020-01-01') ->select();
-
固定查询:
whereyear()
:查询当年默认
|去年last year
|其他年份20xx
的数据$data=Db::table('tp_user') ->whereYear('create_time') ->select();
SELECT * FROM `tp_user` WHERE `create_time` BETWEEN '2020-01-01 00:00:00' AND '2020-12-31 23:59:59'
$data=Db::table('tp_user') ->whereYear('create_time','last year') ->select();
SELECT * FROM `tp_user` WHERE `create_time` BETWEEN '2019-01-01 0:00:00' AND '2019-12-31 23:59:59'
$data=Db::table('tp_user') ->whereYear('create_time','2018') ->select();
SELECT * FROM `tp_user` WHERE `create_time` BETWEEN '2018-01-01 0:00:00' AND '2018-12-31 23:59:59'
-
whereMonth()
查询当月、上月last month
、指定月份(2020-01) -
whereWeek()
查询本周、上周、指定周(以2020-01-01开始的七天) -
whereDay()
查询今天、昨天last Day
、指定日期(2020-01-01) -
精准时间查询(时分秒)
查询指定的时间段
Db::table('tp_user') ->whereBetweenTimeField('start_time','end_time') ->select();
配置
database.php
中的time_query_rule
自定义时间查询规则
时间查询的更多方法建议参考官方文档
聚合查询
count()
:返回所查询数据的数量(可以指定字段,不统计null内容)
Db:table('tp_user')->count();
Db:table('tp_user')->count('delete_time');
SELECT COUNT(`delete_time`) AS think_count FROM `tp_user`
max()/min()
:返回最大/最小值必须指定字段名
$data=Db::table('tp_user')->max('price');
$data=Db::table('tp_user')->min('price');
avg()/sum()
:返回平均值/总和值必须指定字段名
$data=Db::table('tp_user')->avg('price');
$data=Db::table('tp_user')->sum('price');
子查询
fetchSql()
:参数设置是否执行(true|false),默认true不执行sql,而是返回sql语句(默认返回sql语句,不执行sql)且需要执行select()
// 只返回SQL语句,不执行sql操作
Db::table('tp_user')->fetchSql(true)->select();
// 执行sql操作,不返回SQL语句
Db::table('tp_user')->fetchSql(false)->select();
buildSql()
:返回SQL语句且不执行操作,不用执行select()
// 返回SQL语句,并在sql语句两端添加圆括号
Db::table('tp_user')->buildSql(true);
// 返回SQL语句,不添加圆括号
Db::table('tp_user')->buildSql(false);
$subQuery = Db::table('tp_two')
->field('uid')
->where('gender','男')
->buildSql(true);
$data = Db::table('tp_one')
->whereExp('id','IN'.$subQuery)
->select();
SELECT * FROM `tp_one` WHERE ( `id` IN( SELECT `uid` FROM `tp_two` HERE `gender` = '男' ) )
闭包构造子查询
Db::table('tp_one')
->where('id','IN', function($query){
$query->table('tp_two')
->where('gender','男')
->field('uid');
})->select();
SELECT * FROM`tp_one` WHERE`id` IN(SELECT`uid` FROM`tp_two` HERE`gender` ='男')
原生查询
query()
进行原生SQL查询,适用于读取操作
Db::query('select * from tp_user');
execute()
进行原生SQL更新写入
Db::execute('update tp_user set username="柯南" where id=308');
链式操作
建议参考官方文档的介绍,比较详细
连贯操作 | 作用 | 支持的参数类型 |
---|---|---|
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信息 | 数组 |
where
前面接触的where
方法足够了,这里着重的写“数组条件”
关联数组:等值于AND条件
Db::table('tp_user')->where(
[
'gender' => '男',
'uid' => Null,
])->select();
SELECT * FROM `tp_user` WHERE `gender` = '男' AND `uid` IS NULL
索引数组:设置多个AND查询条件
Db::table('tp_user')->where([
['create_time','>','2018'],
['gender','=','男']
])->select();
SELECT * FROM `tp_user` WHERE `create_time` > '2018' AND `gender` = 男'
数组条件也可以提前设置;where中直接引用即可
使用| (OR)
& (AND)
:(支持多个where
,属于AND
连接)
Db::table('tp_user')
->where("username|email",'like','%xiao%')
->where('price&uid','>',0)
->select();
SELECT * FROM `tp_user` WHERE ( `username` LIKE '%xiao%' OR `email` LIKE '%xiao%' ) AND ( `price` > 0 AND `uid` > 0 )
数组方式如果使用exp
查询的话,一定要用raw
方法。
Db::table('think_user')
->where([
['name', 'like', 'thinkphp%'],
['title', 'like', '%thinkphp'],
['id', 'exp', Db::raw('>score')],
['status', '=', 1],
])
->select();
闭包查询可以连缀,会自动加上括号,更清晰,如果是 OR,请用 whereOR();
$user = Db::name('user')
->where(function ($query) {
$query->where('id', '>', 10); })
->whereOr(function ($query) {
$query->where('username', 'like', '%小%');
})->select();
****
field
field()
标识需要返回和操作的字段,可以(采用字符串或数组传递参数)指定一个或多个字段名(select()
不可以使用)
withoutField()
排除指定的字段名,输出其他字段名
fieldRaw()
可以在选定字段操作的同时也可以对字段设置sql函数(例如:um(),avg(),count()……)
官方文档:用于写入
field()
在数据库写入的时候,可以指定对特点的字段进行写入操作,这样一来就会制约变动哪些字段(合法字段验证:文档中说可以校验字段的正确性)
limit
limit
指定查询和操作的数量(分页)
例如获取满足要求的10个用户,如下调用即可:
Db::table('user')
->where('status',1)
->field('id,name')
->limit(10)
->select();
limit
方法也可以用于写操作,例如更新满足要求的3条数据:
Db::table('user')
->where('score',100)
->limit(3)
->update(['level'=>'A']);
如果用于insertAll
方法的话,则可以分批多次写入,每次最多写入limit
方法指定的数
Db::table('user')
->limit(100)
->insertAll($userList);
Db::table('article')->limit(10,25)->select();
表示查询文章数据,从第10行开始的25条数据(可能还取决于where条件和order排序的影响 这个暂且不提)。
对于大数据表,尽量使用limit
限制查询结果,否则会导致很大的内存开销和性能问题。
page
主要应用在分页查询
Db::table('tp_user')->limit(0,10)->select();
Db::table('tp_user')->limit(10,10)->select();
Db::table('tp_user')->page(1,10)->select();
Db::table('tp_user')->page(2,10)->select();
page()
的便利之处显而易见,不需要计算第二页的起始页,系统自动计算。
Db::table('tp_user')->limit(10)->page(1)->select();
order
对操作的结果进行排序
Db::table('user')
->where('status', 1)
->order('id', 'desc')
->limit(5)
->select();
desc
降序 |asc
升序
支持使用数组对多个字段排序
Db::table('user')
->where('status', 1)
->order(['order','id'=>'desc'])
->limit(5)
->select();
group
sql的常用函数,适用分组合计,对一个或多个列的结果集进行分组;接收一个参数(仅字符串)支持多字段分组
Db::table('tp_user')
->fieldRaw('gender,count(username)')
->group('gender')
->select();
having
配合group
的结果从分组总筛选数据(聚合条件)
Db::table('tp_user')
->fieldRaw('gender,count(username)')
->group('gender')
->having('sum(price)>600')
->select();
****
table
table
用于操作指定的数据表
alias
alias
设置当前数据表的别名
Db::table('tp_user')
->alias('user')
->select()
SELECT * FROM `tp_user` `user`
strict
strict()
设置是否严格检查字段名
// 关闭字段严格检查
Db::table('tp_user')
->strict(false)
->insert($data);
系统默认值是由数据库配置参数fields_strict
决定,因此修改数据库配置参数可以进行全局严格检查配置,如下:
// 关闭严格检查字段是否存在
'fields_strict' => false
快捷查询
方法 | 作用 |
---|---|
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 |
根据某个字段获取某个值 |
数据库事务处理
需要表引擎为
InnoDB
transaction()
事务处理:自动处理,出错则自动回滚
Db::transaction(function() {
Db::table('tp_user')
->where('id',19)
->save(['price'=>Db::raw('price-3')]);
Db::table('tp_user')
->where('id',20)
->save(['price'=>Db::raw('price + 3')]);
});
seartTrans()
事务处理:手动处理,可以自行输出错误信息
Db::startTrans();//启动事务处理
try{
Db::table('tp_user')
->where('id',19)
->save(['price'=>Db::raw('price - 3')]);
Db::table('tp_user')
->where('id',20)
->save(['price'=>Db::raw('price + 3')]);
Db::commit();//提交事务(执行)
} catch (\Exception $e){
echo "error".$e;
// 回滚事务
Db::rollback();
}
获取器
将数据的字段进行转换处理在进行操作
withAttr()
传入两个参数(当前字段的值和所有的数据)
$user = Db::table('tp_user')
->withAttr('email',function($value , $data){
return strtoupper($value);
})->select();
return Db::getLastSql() . "
" . $user;
数据集
数据集就是查询后的结果集
// 获取数据集
$users = Db::name('user')->select();
// 遍历数据集
foreach($users as $user){
echo $user['name'];
echo $user['id'];
}
Collection
类包含了下列主要方法:
方法 | 描述 |
---|---|
isEmpty | 是否为空 |
toArray | 转换为数组 |
all | 所有数据 |
merge | 合并其它数据 |
diff | 比较数组,返回差集 |
flip | 交换数据中的键和值 |
intersect | 比较数组,返回交集 |
keys | 返回数据中的所有键名 |
pop | 删除数据中的最后一个元素 |
shift | 删除数据中的第一个元素 |
unshift | 在数据开头插入一个元素 |
push | 在结尾插入一个元素 |
reduce | 通过使用用户自定义函数,以字符串返回数组 |
reverse | 数据倒序重排 |
chunk | 数据分隔为多个数据块 |
each | 给数据的每个元素执行回调 |
filter | 用回调函数过滤数据中的元素 |
column | 返回数据中的指定列 |
sort | 对数据排序 |
order | 指定字段排序 |
shuffle | 将数据打乱 |
slice | 截取数据中的一部分 |
map | 用回调函数处理数组中的元素 |
where | 根据字段条件过滤数组中的元素 |
whereLike | Like查询过滤元素 |
whereNotLike | Not Like过滤元素 |
whereIn | IN查询过滤数组中的元素 |
whereNotIn | Not IN查询过滤数组中的元素 |
whereBetween | Between查询过滤数组中的元素 |
whereNotBetween | Not Between查询过滤数组中的元素 |