在数据库操作的完整链路中,除了基础查询与进阶查询能力外,查询事件的钩子机制、数据获取的格式化处理、事务操作的原子性保障以及数据集的高效处理,共同构成了数据库操作的闭环增强体系,是提升代码健壮性与开发效率的重要支撑。本篇作为数据库系列文章的最后一篇,学习核心内容将集中在查询事件的注册与触发机制、获取器对数据输出的格式化处理、事务操作的开启/提交/回滚流程、以及数据集的遍历与转换等实用功能上。本篇文章将记录 ThinkPHP 数据库操作中这些增强特性的学习过程。
一、查询事件
数据库操作的回调也称为查询事件,是针对数据库的CURD操作而设计的回调方法,主要包括:
事件 |
描述 |
before_select |
select查询前回调 |
before_find |
find查询前回调 |
after_insert |
insert操作成功后回调 |
after_update |
update操作成功后回调 |
after_delete |
delete操作成功后回调 |
使用 Db 类的 event 方法注册数据库查询事件。注册的代码可以写入到 app/AppService.php 中的 register() 服务注册方法中。
示例
// 代码位于 app/AppService.php 中的 register 方法内
public function register()
{
// 注册 before_select 事件
Db::event('before_select', function($query) {
// 事件处理,可以编写对应的处理代码
// 在这里也可以对 $query 进行操作,例如:在当前的 select 查询中对查询结果根据 id 进行 desc 排序
$query->order('id', 'asc');
});
}
不需要在事件中返回任何东西。
同一个查询事件可以注册多个响应执行。查询事件的方法参数只有一个:当前的查询对象。但可以通过依赖注入的方式添加额外的参数。
二、获取器
在 ThinkPHP 中,获取器是用于对字段值进行格式化处理的特殊方法。它允许你在获取字段数据时,自动对原始数据进行加工、转换或处理,而无需在每次使用数据时手动处理。
Db 类可以支持获取器定义,例如:
Db::table('user')->withAttr('name', function($value, $data) {
// 将 name 字段的值会统一进行小写转换
return strtoupper($value);
})
->select();
获取器方法支持传入两个参数,第一个参数是当前字段的值,第二个参数是所有的数据。
withAttr 方法可以多次调用,对多个字段定义获取器。
新版本增加了查询结果处理机制,使用 filter 方法可以更方便的处理查询结果数据:
Db::table('user')->filter(function($user) {
// $user 为当前查询记录
$user['name'] = strtoupper($user['name']); // 将 name 字段的值会统一进行小写转换
return $user; // 需要 return 返回更改的内容
})
->select();
三、事务操作
使用事务处理的话,需要数据库引擎支持事务处理。比如 MySQL 的 MyISAM 不支持事务处理,需要使用 InnoDB 引擎。
最简单的方式是使用 transaction 方法操作数据库事务,当闭包中的代码发生异常会自动回滚。例如:
Db::transaction(function () {
Db::table('user')->find(1);
Db::table('user')->delete(1);
});
也可以手动控制事务。例如:
// startTrans() 方法启动事务
Db::startTrans();
try {
Db::table('user')->find(1);
Db::table('user')->delete(1);
// commit() 方法提交事务
Db::commit();
} catch (\Exception $e) {
// rollback() 方法回滚事务
Db::rollback();
}
注意:在事务操作的时候,确保数据库连接使用的是同一个。
四、数据集
数据库的查询结果默认返回数据集对象。
示例
// 获取数据集
$users = Db::name('user')->select();
// 遍历数据集
foreach($users as $user){
echo $user['name'];
echo $user['id'];
}
返回的数据集对象是 think\Collection,提供了和数组无差别用法,并且另外封装了一些额外的方法。
可以直接使用数组的方式操作数据集对象。例如:
// 获取数据集
$users = Db::name('user')->select();
// 直接操作第一个元素
$item = $users[0];
// 获取数据集记录数
$count = count($users);
// 遍历数据集
foreach($users as $user){
echo $user['name'];
echo $user['id'];
}
需要注意的是,如果要判断数据集是否为空,不能直接使用 empty 方法判断,而必须使用数据集对象的 isEmpty 方法判断。例如:
$users = Db::name('user')->select();
if($users->isEmpty()){
echo '数据集为空';
}
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查询过滤数组中的元素 |