连接数据库
一、配置文件
database.php文件配置
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
];
二、方法配置
Db::connect([
// 数据库类型
'type' => 'mysql',
// 数据库连接DSN配置
'dsn' => '',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
])->table('user')->find();
//字符串连接
Db::connect('mysql://root:1234@127.0.0.1:3306/thinkphp#utf8')
->table('user')
->find();
connect
方法必须在查询的最开始调用,而且必须紧跟着调用查询方法,否则可能会导致部分查询失效或者依然使用默认的数据库连接。
字符串连接的定义格式为:
字符串方式可能无法定义某些参数,例如前缀和连接参数。
实际应用中,我们应当尽量避免把数据库配置信息写在代码中,而应该统一定义在配置文件,我们可以在数据库配置文件中增加额外的配置参数,例如:
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
//数据库配置1
'db_config1' => [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '192.168.1.8',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '1234',
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
],
//数据库配置2
'db_config2' => 'mysql://root:1234@192.168.1.10:3306/thinkphp#utf8',
];
然后需要动态链接的时候使用下面的方式
Db::connect('db_config1')->table('user')->find();
Db::connect('db_config2')->table('user')->find();
动态连接数据库的connect
方法仅对当次查询有效。
这种方式的动态连接和切换数据库比较方便,经常用于多数据库连接的应用需求。
三、模型类定义
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 直接使用配置参数名
protected $connection = 'db_config1';
}
需要注意的是,ThinkPHP的数据库连接是惰性的,所以并不是在实例化的时候就连接数据库,而是在有实际的数据操作的时候才会去连接数据库。
查询构造器
一、查询数据
i 基本查询
1. 单个数据查询
(1)find()
// table方法必须指定完整的数据表名
Db::table('think_user')->where('id',1)->find();
find 方法查询结果不存在,返回 null,否则返回结果数组
(2)findOrFail()
// table方法必须指定完整的数据表名
Db::table('think_user')->where('id',1)->findOrFail();
如果没有查找到数据,则会抛出一个
think\db\exception\DataNotFoundException
异常。
(3)findOrEmpty()
// table方法必须指定完整的数据表名
Db::table('think_user')->where('id',1)->findOrEmpty();
V5.1.23+
版本开始,支持findOrEmpty
方法,当查询不存在的时候返回空数组而不是Null。
2. 查询多个数据(数据集)
(1)select()
Db::table('think_user')->where('status',1)->select();
select 方法查询结果是一个二维数组,如果结果不存在,返回空数组
(2) selectOrFail()
Db::table('think_user')->where('status',1)->selectOrFail();
如果没有查找到数据,同样也会抛出一个
think\db\exception\DataNotFoundException
异常。
注:
如果你的数据表没有设置表前缀的话,那么
name
和table
方法效果一致。
在
find
和select
方法之前可以使用所有的链式操作(参考链式操作章节)方法。默认情况下,find
和select
方法返回的都是数组,区别在于后者是二维数组。
3. 助手函数
系统提供了一个db
助手函数,可以更方便的查询:
db('user')->where('id',1)->find();
db('user')->where('status',1)->select();
db
方法的第一个参数的作用和name
方法一样,如果需要使用不同的数据库连接,可以使用:
db('user','db_config1')->where('id', 1)->find();
ii 值和列查询
1. 查询某个字段的值
// 返回某个字段的值
Db::table('think_user')->where('id',1)->value('name');
value 方法查询结果不存在,返回 null
2. 查询某一列的
// 返回数组
Db::table('think_user')->where('status',1)->column('name');
// 指定id字段的值作为索引
Db::table('think_user')->where('status',1)->column('name','id');
如果要返回完整数据,并且添加一个索引值的话,可以使用
// 指定id字段的值作为索引 返回所有数据
Db::table('think_user')->where('status',1)->column('*','id');
column 方法查询结果不存在,返回空数组
iii 数据分批处理
用户表数据进行分批处理,每次处理 100 个用户记录:
Db::table('think_user')->chunk(100, function($users) {
foreach ($users as $user) {
//
}
});
// 或者交给回调方法myUserIterator处理
Db::table('think_user')->chunk(100, 'myUserIterator');
你可以通过从闭包函数中返回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访问处理大量数据,很容易导致超时。
iiii 大批量数据处理
新版提供的游标查询功能
$cursor = Db::table('user')->where('status', 1)->cursor();
foreach($cursor as $user){
echo $user['name'];
}
cursor
方法返回的是一个生成器对象,user
变量是数据表的一条数据(数组)。
iv JSON类型数据查询(mysql
)
// 查询JSON类型字段 (info字段为json类型)
Db::table('think_user')
->where('info->email','thinkphp@qq.com')
->find();
二、添加数据
1. 添加一条数据
使用 Db
类的 insert
方法向数据库提交数据
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->insert($data);
insert
方法添加数据成功返回添加成功的条数,通常情况返回 1
或者使用data
方法配合insert
使用。
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')
->data($data)
->insert();
如果你的数据表里面没有
foo
或者bar
字段,那么就会抛出异常。
如果不希望抛出异常,可以使用下面的方法:
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->strict(false)->insert($data);
不存在的字段的值将会直接抛弃。
如果是mysql数据库,支持replace
写入(若存在则更新,若不存在则插入),例如:
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->insert($data, true);
添加数据后如果需要返回新增数据的自增主键,可以使用insertGetId
方法新增数据并返回主键值:
$userId = Db::name('user')->insertGetId($data);
2. 添加多条数据
添加多条数据直接向 Db 类的 insertAll
方法传入需要添加的数据即可
$data = [
['foo' => 'bar', 'bar' => 'foo'],
['foo' => 'bar1', 'bar' => 'foo1'],
['foo' => 'bar2', 'bar' => 'foo2']
];
Db::name('user')->insertAll($data);
insertAll 方法添加数据成功返回添加成功的条数
如果是mysql数据库,支持replace
写入,例如:
$data = [
['foo' => 'bar', 'bar' => 'foo'],
['foo' => 'bar1', 'bar' => 'foo1'],
['foo' => 'bar2', 'bar' => 'foo2']
];
Db::name('user')->insertAll($data, true);
也可以使用data
方法
$data = [
['foo' => 'bar', 'bar' => 'foo'],
['foo' => 'bar1', 'bar' => 'foo1'],
['foo' => 'bar2', 'bar' => 'foo2']
];
Db::name('user')->data($data)->insertAll();
确保要批量添加的数据字段是一致的
如果批量插入的数据比较多,可以指定分批插入,使用limit
方法指定每次插入的数量限制。
$data = [
['foo' => 'bar', 'bar' => 'foo'],
['foo' => 'bar1', 'bar' => 'foo1'],
['foo' => 'bar2', 'bar' => 'foo2']
...
];
// 分批写入 每次最多100条数据
Db::name('user')->data($data)->limit(100)->insertAll();
三、更新数据
1. 更新数据
Db::name('user')
->where('id', 1)
->update(['name' => 'thinkphp']);
update 方法返回影响数据的条数,没修改任何数据返回 0
支持使用data
方法传入要更新的数据
Db::name('user')
->where('id', 1)
->data(['name' => 'thinkphp'])
->update();
如果数据中包含主键,可以直接使用:
Db::name('user')
->update(['name' => 'thinkphp','id'=>1]);
如果要更新的数据需要使用SQL
函数或者其它字段,可以使用下面的方式:
Db::name('user')
->where('id',1)
->inc('read_time')
->dec('score',3)
->exp('name','UPPER(name)')
->update();
V5.1.7+
版本以后,支持使用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')
]);
2. 更新字段值
(1)setField ()
Db::name('user')
->where('id',1)
->setField('name', 'thinkphp');
setField 方法返回影响数据的条数,没修改任何数据字段返回 0
(2)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);
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();
delete 方法返回影响数据的条数,没有删除返回 0
如果不带任何条件调用delete
方法会提示错误,如果你确实需要删除所有数据,可以使用
// 无条件删除所有数据
Db::name('user')->delete(true);
五、查询表达式
查询表达式支持大部分的SQL查询语法,也是ThinkPHP
查询语言的精髓,查询表达式的使用格式:
where('字段名','表达式','查询条件');
whereOr('字段名','表达式','查询条件');
5.1
还支持新的查询方法
whereField('表达式','查询条件');
whereOrField('表达式','查询条件');
Field
使用字段的驼峰命名方式。
表达式不分大小写,支持的查询表达式有下面几种:
表达式 | 含义 | 快捷查询方法 |
---|---|---|
= | 等于 | |
<> | 不等于 | |
> | 大于 | |
>= | 大于等于 | |
< | 小于 | |
<= | 小于等于 | |
[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] BETWEEM TIME | 时间区间比较 | whereBetweenTime |
> TIME | 大于某个时间 | whereTime |
< TIME | 小于某个时间 | whereTime |
>= TIME | 大于等于某个时间 | whereTime |
<= TIME | 小于等于某个时间 | whereTime |
EXP | 表达式查询,支持SQL语法 | whereExp |
注:
1. like
查询支持使用数组
Db::name('user')->where('name','like',['%think','php%'],'OR')->select();
//实际生成的SQL语句为
SELECT * FROM `think_user` WHERE (`name` LIKE '%think' OR `name` LIKE 'php%')
2. between
Db::name('user')->where('id','between','1,8')->select();
//等效
Db::name('user')->where('id','between',[1,8])->select();
3. in
Db::name('user')->where('id','between',[1,8])->select();
//等效
Db::name('user')->where('id','in',[1,5,8])->select();
4. exp
Db::name('user')->where('id','exp',' IN (1,3,8) ')->select();
exp
查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。
5. whereField()
Db::name('user')->whereId('>=',100)->select();
六、链式操作
链式操作方法,除了
select
方法必须放到最后一个外(因为select
方法并不是链式操作方法),链式操作的方法调用顺序没有先后
1. where
(1)表达式
Db::table('think_user')
->where('id','>',1)
->where('name','thinkphp')
->select();
(2)数组
关联数组
// 传入数组作为查询条件
Db::table('think_user')->where([
'name' => 'thinkphp',
'status'=> [1, 2]
])->select();
索引数组
// 传入数组作为查询条件
Db::table('think_user')->where([
['name','=','thinkphp'],
['status','=',1]
])->select();
组装数组
$map[] = ['name','like','think'];
$map[] = ['status','=',1];
(3)字符串
Db::table('think_user')->where('type=1 AND status=1')->select();
注意使用字符串查询条件和表达式查询的一个区别在于,不会对查询字段进行避免关键词冲突处理。
2. table
- 切换操作的数据表;
- 对多表进行操作;
Db::table('think_user')->where('status>1')->select();
//指定数据库
Db::table('db_name.think_user')->where('status>1')->select();
name
方式简化数据表前缀的传入,会自动获取当前模型对应的数据表前缀来生成think_user
数据表名称。
Db::name('user')->where('status>1')->select();
3. alias
用于设置当前数据表的别名,便于使用其他的连贯操作例如join方法等。
Db::table('think_user')
->alias('a')
->join('think_dept b ','b.user_id= a.id')
->select();
//传入数组批量设置数据表以及别名
Db::table('think_user')
->alias(['think_user'=>'user','think_dept'=>'dept'])
->join('think_dept','dept.user_id= user.id')
->select();
//field可以给某个字段设置别名
Db::table('think_user')->field('id,nickname as name')->select();
4. field
//指定字段
Db::table('think_user')->field('id,nickname as name')->select();
//使用SQL函数
Db::table('think_user')->field('id,SUM(score)')->select();
//V5.1.7+版本开始,如果需要使用SQL函数,推荐使用下面的方式
Db::table('think_user')->fieldRaw('id,SUM(score)')->select();
//使用数组参数
Db::table('think_user')->field(['id','title','content'])->select();
//数组方式的定义可以为某些字段定义别名
Db::table('think_user')->field(['id','nickname'=>'name'])->select();
//获取所有字段
Db::table('think_user')->select();
Db::table('think_user')->field('*')->select();
//字段排除
//获取除了content之外的所有字段
Db::table('think_user')->field('content',true)->select();
//用于写入
Db::table('think_user')->field('title,email,content')->insert($data);
5. strict
// 关闭字段严格检查
Db::name('user')
->strict(false)
->insert($data);
// 关闭严格检查字段是否存在
'fields_strict' => false,
如果开启字段严格检查的话,在更新和写入数据库的时候,一旦存在非数据表字段的值,则会抛出异常。
6. limit
//限制结果数量
Db::table('think_user')
->where('status',1)
->field('id,name')
->limit(10)
->select();
//分页查询
Db::table('think_article')->limit(10,25)->select();
7. page
Db::table('think_article')->limit(25)->page(3)->select();'
//等同于
Db::table('think_article')->page(3,25)->select();
8. oder
Db::table('think_user')
->where('status', 1)
->order(['order','id'=>'desc'])
->limit(5)
->select();
//在V5.1.7+版本开始,如果你需要在order方法中使用mysql函数的话,必须使用下面的方式:
Db::table('think_user')
->where('status', 1)
->orderRaw("field(name,'thinkphp','onethink','kancloud')")
->limit(5)
->select();
9. group
Db::table('think_user')
->field('user_id,test_time,username,max(score)')
->group('user_id,test_time')
->select();
10. having
Db::table('think_user')
->field('username,max(score)')
->group('user_id')
->having('count(test_time)>3')
->select();
11. join
join ( mixed join [, mixed $condition = null [, string $type = 'INNER']] )
leftJoin ( mixed join [, mixed $condition = null ] )
rightJoin ( mixed join [, mixed $condition = null ] )
fullJoin ( mixed join [, mixed $condition = null ] )
Db::table('think_user')
->alias('a')
->join(['think_work'=>'w'],'a.id=w.artist_id')
->join(['think_card'=>'c'],'a.card_id=c.id')
->select();
12. UNION
操作用于合并两个或多个 SELECT 语句的结果集。
使用示例:
Db::field('name')
->table('think_user_0')
->union('SELECT name FROM think_user_1')
->union('SELECT name FROM think_user_2')
->select();
//闭包用法:
Db::field('name')
->table('think_user_0')
->union(function ($query) {
$query->field('name')->table('think_user_1');
})
->union(function ($query) {
$query->field('name')->table('think_user_2');
})
->select();
//或者
Db::field('name')
->table('think_user_0')
->union([
'SELECT name FROM think_user_1',
'SELECT name FROM think_user_2',
])
->select();
//支持UNION ALL 操作,例如:
Db::field('name')
->table('think_user_0')
->unionAll('SELECT name FROM think_user_1')
->unionAll('SELECT name FROM think_user_2')
->select();
//或者
Db::field('name')
->table('think_user_0')
->union(['SELECT name FROM think_user_1', 'SELECT name FROM think_user_2'], true)
->select();
13. distinct
Db::table('think_user')->distinct(true)->field('user_login')->select();
14. cache
//默认情况下, 缓存有效期是由默认的缓存配置参数决定的,但cache方法可以单独指定,例如:
Db::table('think_user')->cache(true,60)->find();
// 或者使用下面的方式 是等效的
Db::table('think_user')->cache(60)->find();
//表示对查询结果的缓存有效期60秒。
//cache方法可以指定缓存标识:
Db::table('think_user')->cache('key',60)->find();
//指定查询缓存的标识可以使得查询缓存更有效率。
//这样,在外部就可以通过\think\Cache类直接获取查询缓存的数据,例如:
$result = Db::table('think_user')->cache('key',60)->find();
$data = \think\Cache::get('key');
//cache方法支持设置缓存标签,例如:
Db::table('think_user')->cache('key',60,'tagName')->find();
七、聚合查询
方法 | 说明 |
---|---|
count | 统计数量,参数是要统计的字段名(可选) |
max | 获取最大值,参数是要统计的字段名(必须) |
min | 获取最小值,参数是要统计的字段名(必须) |
avg | 获取平均值,参数是要统计的字段名(必须) |
sum | 获取总分,参数是要统计的字段名(必须) |
Db::table('think_user')->count('id');
Db::table('think_user')->max('score');
//如果你要获取的最大值不是一个数值,可以使用第二个参数关闭强制转换
Db::table('think_user')->max('name',false);
Db::table('think_user')->where('score', '>', 0)->min('name',false);
Db::table('think_user')->avg('score');
Db::table('think_user')->where('id',10)->sum('score');
八、时间查询
1. where
// 大于某个时间
where('create_time', '> time', '2016-1-1');
// 小于某个时间
where('create_time', '<= time', '2016-1-1');
// 时间区间查询
where('create_time', 'between time', ['2015-1-1', '2016-1-1']);
2. whereTime
// 大于某个时间
Db::name('user')
->whereTime('birthday', '>=', '1970-10-1')
->select();
// 小于某个时间
Db::name('user')
->whereTime('birthday', '<', '2000-10-1')
->select();
// 时间区间查询
Db::name('user')
->whereTime('birthday', 'between', ['1970-10-1', '2000-10-1'])
->select();
// 不在某个时间区间
Db::name('user')
->whereTime('birthday', 'not between', ['1970-10-1', '2000-10-1'])
->select();
3. whereBetweenTime
// 查询2017年上半年注册的用户
Db::name('user')
->whereBetweenTime('create_time', '2017-01-01', '2017-06-30')
->select();
// 查询2017年6月1日注册的用户
Db::name('user')
->whereBetweenTime('create_time', '2017-06-01')
->select();
4. whereBetweenTimeField
// 查询有效期内的活动
Db::name('event')
->whereBetweenTimeField('start_time','end_time')
->select();
//查询相当于
Db::name('event')
->whereTime('start_time', '<=', time())
->whereTime('end_time', '>=', time())
->select();
5. 时间表达式
还提供了更方便的时间表达式查询,例如:
// 获取今天的博客
Db::name('blog')
->whereTime('create_time', 'today')
->select();
// 获取昨天的博客
Db::name('blog')
->whereTime('create_time', 'yesterday')
->select();
// 获取本周的博客
Db::name('blog')
->whereTime('create_time', 'week')
->select();
// 获取上周的博客
Db::name('blog')
->whereTime('create_time', 'last week')
->select();
// 获取本月的博客
Db::name('blog')
->whereTime('create_time', 'month')
->select();
// 获取上月的博客
Db::name('blog')
->whereTime('create_time', 'last month')
->select();
// 获取今年的博客
Db::name('blog')
->whereTime('create_time', 'year')
->select();
// 获取去年的博客
Db::name('blog')
->whereTime('create_time', 'last year')
->select();
//如果查询当天、本周、本月和今年的时间,还可以简化为:
// 获取今天的博客
Db::name('blog')
->whereTime('create_time', 'd')
->select();
// 获取本周的博客
Db::name('blog')
->whereTime('create_time', 'w')
->select();
// 获取本月的博客
Db::name('blog')
->whereTime('create_time', 'm')
->select();
// 获取今年的博客
Db::name('blog')
->whereTime('create_time', 'y')
->select();
//时间表达式进行时间查询
// 查询两个小时内的博客
Db::name('blog')
->whereTime('create_time','-2 hours')
->select();
九、高级查询
1. 快捷查询
快捷查询支持所有的查询表达式。
Db::table('think_user')
->where('name|title','like','thinkphp%')
->where('create_time&update_time','>',0)
->find();
2. 区间查询
区间查询的查询条件必须使用数组定义方式,支持所有的查询表达式。
Db::table('think_user')
->where('name', ['like', '%thinkphp%'], ['like', '%kancloud%'], 'or')
->where('id', ['>', 0], ['<>', 10], 'and')
->find();
//代替
Db::table('think_user')
->where('name', 'like', '%think%')
->where('name', 'like', '%php%')
->where('id', 'in', [1, 5, 80, 50])
->where('id', '>', 10)
->find();
3. 批量(字段)查询
Db::table('think_user')
->where([
['name', 'like', 'thinkphp%'],
['title', 'like', '%thinkphp'],
['id', '>', 0],
['status', '=', 1],
])
->select();
注意,相同的字段的多次查询条件可能会合并,如果希望某一个
where
方法里面的条件单独处理,可以使用下面的方式,避免被其它条件影响。
$map = [
['name', 'like', 'thinkphp%'],
['title', 'like', '%thinkphp'],
['id', '>', 0],
];
Db::table('think_user')
->where([ $map ])
->where('status',1)
->select();
4. 动态查询
动态查询 | 描述 |
---|---|
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');
5. 条件查询
Db::name('user')->when($condition, function ($query) {
// 满足条件后执行
$query->where('score', '>', 80)->limit(10);
}, function ($query) {
// 不满足条件执行
$query->where('score', '>', 60);
});
十、子查询
1. fetchSql
fetchSql方法表示不进行查询而只是返回构建的SQL语句
$subQuery = Db::table('think_user')
->field('id,name')
->where('id', '>', 10)
->fetchSql(true)
->select();
2. buildSql
//使用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();
3. 使用闭包构造子查询
IN/NOT IN
和EXISTS/NOT EXISTS
之类的查询可以直接使用闭包作为子查询,例如:
Db::table('think_user')
->where('id', 'IN', function ($query) {
$query->table('think_profile')->where('status', 1)->field('id');
})
->select();
十一、原生查询
1. query
Db::query("select * from think_user where status=1");
query
方法用于执行SQL
查询操作,如果数据非法或者查询错误则返回false,否则返回查询结果数据集(同select
方法)。
2. execute
Db::execute("update think_user set name='thinkphp' where status=1");
execute
用于更新和写入数据的sql操作,如果数据非法或者查询错误则返回false
,否则返回影响的记录数。
查询事件
一、查询事件
数据库的CURD操作支持事件,包括:
事件 | 描述 |
---|---|
before_select | select 查询前回调 |
before_find | find 查询前回调 |
after_insert | insert 操作成功后回调 |
after_update | update 操作成功后回调 |
after_delete | delete 操作成功后回调 |
查询事件仅支持find
、select
、insert
、update
和delete
方法。
二、注册事件
使用下面的方法注册数据库查询事件
Db::event('after_insert', 'callback');
Db::event('before_select', function ($query) {
// 事件处理
return $result;
});
获取器
Db类也可以支持获取器定义,例如:
Db::name('user')->withAttr('name', function($value, $data) {
return strtolower($value);
})->select();
上面的代码,查询的数据集数据中的name
字段的值会统一进行小写转换。
withAttr
方法可以多次调用,对多个字段定义获取器。
事务操作
最简单的方式是使用 transaction
方法操作数据库事务,当闭包中的代码发生异常会自动回滚,例如:
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();
}
注意在事务操作的时候,确保你的数据库连接使用的是同一个。
事务内使用db()无法回滚
存储过程
数据访问层支持存储过程调用,调用数据库存储过程使用下面的方法:
$resultSet = Db::query('call procedure_name');
foreach ($resultSet as $result) {
}
存储过程返回的是一个数据集,如果你的存储过程不需要返回任何的数据,那么也可以使用execute方法:
Db::execute('call procedure_name');
存储过程可以支持输入和输出参数,以及进行参数绑定操作。
$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],
]);
输出参数的绑定必须额外使用PDO::PARAM_INPUT_OUTPUT
,并且可以和输入参数公用一个参数。
无论存储过程内部做了什么操作,每次存储过程调用仅仅被当成一次查询。
数据集
数据库的查询结果也就是数据集,默认的配置下,数据集的类型是一个二维数组,我们可以配置成数据集类,就可以支持对数据集更多的对象化操作,需要使用数据集类功能,可以配置数据库的
resultset_type
参数
// 数据集返回类型
'resultset_type' => 'collection',
在模型中进行数据集查询,全部返回数据集对象,但使用的是
think\model\Collection
类,但用法是一致的。
需要注意的是,如果要判断数据集是否为空,不能直接使用empty
判断,而必须使用数据集对象的isEmpty
方法判断,例如:
$users = Db::name('user')->select();
if($users->isEmpty()){
echo '数据集为空';
}
方法 | 描述 |
---|---|
isEmpty | 是否为空 |
toArray | 转换为数组 |
all | 所有数据 |
merge | 合并其它数据 |
diff | 比较数组,返回差集 |
flip | 交换数据中的键和值 |
intersect | 比较数组,返回交集 |
keys | 返回数据中的所有键名 |
pop | 删除数据中的最后一个元素 |
shift | 删除数据中的第一个元素 |
unshift | 在数据开头插入一个元素 |
reduce | 通过使用用户自定义函数,以字符串返回数组 |
reverse | 数据倒序重排 |
chunk | 数据分隔为多个数据块 |
each | 给数据的每个元素执行回调 |
filter | 用回调函数过滤数据中的元素 |
column | 返回数据中的指定列 |
sort | 对数据排序 |
shuffle | 将数据打乱 |
slice | 截取数据中的一部分 |